1   /**
2    * Copyright (c) 2000-2007 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portlet.journal.service.impl;
24  
25  import com.liferay.counter.service.CounterLocalServiceUtil;
26  import com.liferay.mail.service.MailServiceUtil;
27  import com.liferay.portal.PortalException;
28  import com.liferay.portal.SystemException;
29  import com.liferay.portal.kernel.mail.MailMessage;
30  import com.liferay.portal.kernel.search.Hits;
31  import com.liferay.portal.kernel.servlet.ImageServletTokenUtil;
32  import com.liferay.portal.kernel.util.ContentTypes;
33  import com.liferay.portal.kernel.util.GetterUtil;
34  import com.liferay.portal.kernel.util.LocaleUtil;
35  import com.liferay.portal.kernel.util.OrderByComparator;
36  import com.liferay.portal.kernel.util.StringMaker;
37  import com.liferay.portal.kernel.util.StringPool;
38  import com.liferay.portal.kernel.util.StringUtil;
39  import com.liferay.portal.kernel.util.Validator;
40  import com.liferay.portal.lucene.LuceneFields;
41  import com.liferay.portal.lucene.LuceneUtil;
42  import com.liferay.portal.model.Company;
43  import com.liferay.portal.model.Image;
44  import com.liferay.portal.model.User;
45  import com.liferay.portal.model.impl.ResourceImpl;
46  import com.liferay.portal.service.PortletPreferencesLocalServiceUtil;
47  import com.liferay.portal.service.ResourceLocalServiceUtil;
48  import com.liferay.portal.service.impl.ImageLocalUtil;
49  import com.liferay.portal.service.persistence.CompanyUtil;
50  import com.liferay.portal.service.persistence.UserUtil;
51  import com.liferay.portal.servlet.filters.layoutcache.LayoutCacheUtil;
52  import com.liferay.portal.theme.ThemeDisplay;
53  import com.liferay.portal.util.PortalUtil;
54  import com.liferay.portal.util.PortletKeys;
55  import com.liferay.portlet.journal.ArticleContentException;
56  import com.liferay.portlet.journal.ArticleDisplayDateException;
57  import com.liferay.portlet.journal.ArticleExpirationDateException;
58  import com.liferay.portlet.journal.ArticleIdException;
59  import com.liferay.portlet.journal.ArticleReviewDateException;
60  import com.liferay.portlet.journal.ArticleTitleException;
61  import com.liferay.portlet.journal.ArticleTypeException;
62  import com.liferay.portlet.journal.DuplicateArticleIdException;
63  import com.liferay.portlet.journal.NoSuchArticleException;
64  import com.liferay.portlet.journal.NoSuchArticleResourceException;
65  import com.liferay.portlet.journal.NoSuchTemplateException;
66  import com.liferay.portlet.journal.job.CheckArticleJob;
67  import com.liferay.portlet.journal.model.JournalArticle;
68  import com.liferay.portlet.journal.model.JournalArticleDisplay;
69  import com.liferay.portlet.journal.model.JournalTemplate;
70  import com.liferay.portlet.journal.model.impl.JournalArticleDisplayImpl;
71  import com.liferay.portlet.journal.model.impl.JournalArticleImpl;
72  import com.liferay.portlet.journal.service.JournalArticleImageLocalServiceUtil;
73  import com.liferay.portlet.journal.service.JournalArticleResourceLocalServiceUtil;
74  import com.liferay.portlet.journal.service.JournalContentSearchLocalServiceUtil;
75  import com.liferay.portlet.journal.service.base.JournalArticleLocalServiceBaseImpl;
76  import com.liferay.portlet.journal.service.persistence.JournalArticleFinder;
77  import com.liferay.portlet.journal.service.persistence.JournalArticleUtil;
78  import com.liferay.portlet.journal.service.persistence.JournalStructureUtil;
79  import com.liferay.portlet.journal.service.persistence.JournalTemplateUtil;
80  import com.liferay.portlet.journal.util.Indexer;
81  import com.liferay.portlet.journal.util.JournalUtil;
82  import com.liferay.portlet.journal.util.comparator.ArticleDisplayDateComparator;
83  import com.liferay.portlet.journalcontent.util.JournalContentUtil;
84  import com.liferay.portlet.messageboards.service.MBMessageLocalServiceUtil;
85  import com.liferay.portlet.ratings.service.RatingsStatsLocalServiceUtil;
86  import com.liferay.portlet.tags.service.TagsAssetLocalServiceUtil;
87  import com.liferay.util.LocalizationUtil;
88  import com.liferay.util.MathUtil;
89  import com.liferay.util.lucene.HitsImpl;
90  
91  import java.io.IOException;
92  import java.io.StringReader;
93  import java.io.UnsupportedEncodingException;
94  
95  import java.util.Collections;
96  import java.util.Date;
97  import java.util.HashSet;
98  import java.util.Iterator;
99  import java.util.List;
100 import java.util.Map;
101 import java.util.Set;
102 
103 import javax.mail.internet.InternetAddress;
104 
105 import javax.portlet.PortletPreferences;
106 
107 import org.apache.commons.logging.Log;
108 import org.apache.commons.logging.LogFactory;
109 import org.apache.lucene.index.IndexWriter;
110 import org.apache.lucene.search.BooleanClause;
111 import org.apache.lucene.search.BooleanQuery;
112 import org.apache.lucene.search.Searcher;
113 import org.apache.lucene.search.Sort;
114 import org.apache.lucene.search.SortField;
115 
116 import org.dom4j.Document;
117 import org.dom4j.DocumentException;
118 import org.dom4j.Element;
119 import org.dom4j.io.SAXReader;
120 
121 import org.htmlparser.util.ParserException;
122 import org.htmlparser.util.ParserUtils;
123 
124 /**
125  * <a href="JournalArticleLocalServiceImpl.java.html"><b><i>View Source</i></b>
126  * </a>
127  *
128  * @author Brian Wing Shun Chan
129  *
130  */
131 public class JournalArticleLocalServiceImpl
132     extends JournalArticleLocalServiceBaseImpl {
133 
134     public JournalArticle addArticle(
135             long userId, String articleId, boolean autoArticleId, long plid,
136             String title, String description, String content, String type,
137             String structureId, String templateId, int displayDateMonth,
138             int displayDateDay, int displayDateYear, int displayDateHour,
139             int displayDateMinute, int expirationDateMonth,
140             int expirationDateDay, int expirationDateYear,
141             int expirationDateHour, int expirationDateMinute,
142             boolean neverExpire, int reviewDateMonth, int reviewDateDay,
143             int reviewDateYear, int reviewDateHour, int reviewDateMinute,
144             boolean neverReview, boolean indexable, Map images,
145             String articleURL, PortletPreferences prefs, String[] tagsEntries,
146             boolean addCommunityPermissions, boolean addGuestPermissions)
147         throws PortalException, SystemException {
148 
149         return addArticle(
150             userId, articleId, autoArticleId, plid, title, description, content,
151             type, structureId, templateId, displayDateMonth, displayDateDay,
152             displayDateYear, displayDateHour, displayDateMinute,
153             expirationDateMonth, expirationDateDay, expirationDateYear,
154             expirationDateHour, expirationDateMinute, neverExpire,
155             reviewDateMonth, reviewDateDay, reviewDateYear, reviewDateHour,
156             reviewDateMinute, neverReview, indexable, images, articleURL, prefs,
157             tagsEntries, Boolean.valueOf(addCommunityPermissions),
158             Boolean.valueOf(addGuestPermissions), null, null);
159     }
160 
161     public JournalArticle addArticle(
162             long userId, String articleId, boolean autoArticleId, long plid,
163             String title, String description, String content, String type,
164             String structureId, String templateId, int displayDateMonth,
165             int displayDateDay, int displayDateYear, int displayDateHour,
166             int displayDateMinute, int expirationDateMonth,
167             int expirationDateDay, int expirationDateYear,
168             int expirationDateHour, int expirationDateMinute,
169             boolean neverExpire, int reviewDateMonth, int reviewDateDay,
170             int reviewDateYear, int reviewDateHour, int reviewDateMinute,
171             boolean neverReview, boolean indexable, Map images,
172             String articleURL, PortletPreferences prefs, String[] tagsEntries,
173             String[] communityPermissions, String[] guestPermissions)
174         throws PortalException, SystemException {
175 
176         return addArticle(
177             userId, articleId, autoArticleId, plid, title, description, content,
178             type, structureId, templateId, displayDateMonth, displayDateDay,
179             displayDateYear, displayDateHour, displayDateMinute,
180             expirationDateMonth, expirationDateDay, expirationDateYear,
181             expirationDateHour, expirationDateMinute, neverExpire,
182             reviewDateMonth, reviewDateDay, reviewDateYear, reviewDateHour,
183             reviewDateMinute, neverReview, indexable, images, articleURL, prefs,
184             tagsEntries, null, null, communityPermissions, guestPermissions);
185     }
186 
187     public JournalArticle addArticle(
188             long userId, String articleId, boolean autoArticleId, long plid,
189             String title, String description, String content, String type,
190             String structureId, String templateId, int displayDateMonth,
191             int displayDateDay, int displayDateYear, int displayDateHour,
192             int displayDateMinute, int expirationDateMonth,
193             int expirationDateDay, int expirationDateYear,
194             int expirationDateHour, int expirationDateMinute,
195             boolean neverExpire, int reviewDateMonth, int reviewDateDay,
196             int reviewDateYear, int reviewDateHour, int reviewDateMinute,
197             boolean neverReview, boolean indexable, Map images,
198             String articleURL, PortletPreferences prefs, String[] tagsEntries,
199             Boolean addCommunityPermissions, Boolean addGuestPermissions,
200             String[] communityPermissions, String[] guestPermissions)
201         throws PortalException, SystemException {
202 
203         long groupId = PortalUtil.getPortletGroupId(plid);
204 
205         return addArticleToGroup(
206             userId, articleId, autoArticleId, groupId, title, description,
207             content, type, structureId, templateId, displayDateMonth,
208             displayDateDay, displayDateYear, displayDateHour, displayDateMinute,
209             expirationDateMonth, expirationDateDay, expirationDateYear,
210             expirationDateHour, expirationDateMinute, neverExpire,
211             reviewDateMonth, reviewDateDay, reviewDateYear, reviewDateHour,
212             reviewDateMinute, neverReview, indexable, images, articleURL,
213             prefs, tagsEntries, addCommunityPermissions, addGuestPermissions,
214             communityPermissions, guestPermissions);
215     }
216 
217     public JournalArticle addArticleToGroup(
218             long userId, String articleId, boolean autoArticleId, long groupId,
219             String title, String description, String content, String type,
220             String structureId, String templateId, int displayDateMonth,
221             int displayDateDay, int displayDateYear, int displayDateHour,
222             int displayDateMinute, int expirationDateMonth,
223             int expirationDateDay, int expirationDateYear,
224             int expirationDateHour, int expirationDateMinute,
225             boolean neverExpire, int reviewDateMonth, int reviewDateDay,
226             int reviewDateYear, int reviewDateHour, int reviewDateMinute,
227             boolean neverReview, boolean indexable, Map images,
228             String articleURL, PortletPreferences prefs, String[] tagsEntries,
229             Boolean addCommunityPermissions, Boolean addGuestPermissions,
230             String[] communityPermissions, String[] guestPermissions)
231         throws PortalException, SystemException {
232 
233         // Article
234 
235         User user = UserUtil.findByPrimaryKey(userId);
236         articleId = articleId.trim().toUpperCase();
237         Date now = new Date();
238 
239         Date displayDate = PortalUtil.getDate(
240             displayDateMonth, displayDateDay, displayDateYear,
241             displayDateHour, displayDateMinute, user.getTimeZone(),
242             new ArticleDisplayDateException());
243 
244         Date expirationDate = null;
245 
246         if (!neverExpire) {
247             expirationDate = PortalUtil.getDate(
248                 expirationDateMonth, expirationDateDay, expirationDateYear,
249                 expirationDateHour, expirationDateMinute, user.getTimeZone(),
250                 new ArticleExpirationDateException());
251         }
252 
253         Date reviewDate = null;
254 
255         if (!neverReview) {
256             reviewDate = PortalUtil.getDate(
257                 reviewDateMonth, reviewDateDay, reviewDateYear, reviewDateHour,
258                 reviewDateMinute, user.getTimeZone(),
259                 new ArticleReviewDateException());
260         }
261 
262         validate(
263             groupId, articleId, autoArticleId, title, content, type,
264             structureId, templateId);
265 
266         if (autoArticleId) {
267             articleId = String.valueOf(CounterLocalServiceUtil.increment());
268         }
269 
270         long id = CounterLocalServiceUtil.increment();
271 
272         long resourcePrimKey =
273             JournalArticleResourceLocalServiceUtil.getArticleResourcePrimKey(
274                 groupId, articleId);
275 
276         JournalArticle article = JournalArticleUtil.create(id);
277 
278         content = format(
279             groupId, articleId, article.getVersion(), false, content,
280             structureId, images);
281 
282         article.setResourcePrimKey(resourcePrimKey);
283         article.setGroupId(groupId);
284         article.setCompanyId(user.getCompanyId());
285         article.setUserId(user.getUserId());
286         article.setUserName(user.getFullName());
287         article.setCreateDate(now);
288         article.setModifiedDate(now);
289         article.setArticleId(articleId);
290         article.setVersion(JournalArticleImpl.DEFAULT_VERSION);
291         article.setTitle(title);
292         article.setDescription(description);
293         article.setContent(content);
294         article.setType(type);
295         article.setStructureId(structureId);
296         article.setTemplateId(templateId);
297         article.setDisplayDate(displayDate);
298         article.setApproved(false);
299 
300         if ((expirationDate == null) || expirationDate.after(now)) {
301             article.setExpired(false);
302         }
303         else {
304             article.setExpired(true);
305         }
306 
307         article.setExpirationDate(expirationDate);
308         article.setReviewDate(reviewDate);
309         article.setIndexable(indexable);
310 
311         JournalArticleUtil.update(article);
312 
313         // Resources
314 
315         if ((addCommunityPermissions != null) &&
316             (addGuestPermissions != null)) {
317 
318             addArticleResources(
319                 article, addCommunityPermissions.booleanValue(),
320                 addGuestPermissions.booleanValue());
321         }
322         else {
323             addArticleResources(
324                 article, communityPermissions, guestPermissions);
325         }
326 
327         // Tags
328 
329         updateTagsAsset(userId, article, tagsEntries);
330 
331         // Email
332 
333         sendEmail(article, articleURL, prefs, "requested");
334 
335         return article;
336     }
337 
338     public void addArticleResources(
339             long groupId, String articleId, boolean addCommunityPermissions,
340             boolean addGuestPermissions)
341         throws PortalException, SystemException {
342 
343         JournalArticle article = getLatestArticle(groupId, articleId);
344 
345         addArticleResources(
346             article, addCommunityPermissions, addGuestPermissions);
347     }
348 
349     public void addArticleResources(
350             JournalArticle article, boolean addCommunityPermissions,
351             boolean addGuestPermissions)
352         throws PortalException, SystemException {
353 
354         ResourceLocalServiceUtil.addResources(
355             article.getCompanyId(), article.getGroupId(),
356             article.getUserId(), JournalArticle.class.getName(),
357             article.getResourcePrimKey(), false, addCommunityPermissions,
358             addGuestPermissions);
359     }
360 
361     public void addArticleResources(
362             long groupId, String articleId, String[] communityPermissions,
363             String[] guestPermissions)
364         throws PortalException, SystemException {
365 
366         JournalArticle article = getLatestArticle(groupId, articleId);
367 
368         addArticleResources(article, communityPermissions, guestPermissions);
369     }
370 
371     public void addArticleResources(
372             JournalArticle article, String[] communityPermissions,
373             String[] guestPermissions)
374         throws PortalException, SystemException {
375 
376         ResourceLocalServiceUtil.addModelResources(
377             article.getCompanyId(), article.getGroupId(),
378             article.getUserId(), JournalArticle.class.getName(),
379             article.getResourcePrimKey(), communityPermissions,
380             guestPermissions);
381     }
382 
383     public JournalArticle approveArticle(
384             long userId, long groupId, String articleId, double version,
385             String articleURL, PortletPreferences prefs)
386         throws PortalException, SystemException {
387 
388         // Article
389 
390         User user = UserUtil.findByPrimaryKey(userId);
391         Date now = new Date();
392 
393         JournalArticle article = JournalArticleUtil.findByG_A_V(
394             groupId, articleId, version);
395 
396         article.setModifiedDate(now);
397         article.setApproved(true);
398         article.setApprovedByUserId(user.getUserId());
399         article.setApprovedByUserName(user.getFullName());
400         article.setApprovedDate(now);
401 
402         JournalArticleUtil.update(article);
403 
404         // Email
405 
406         sendEmail(article, articleURL, prefs, "granted");
407 
408         // Lucene
409 
410         try {
411             if (article.isIndexable()) {
412                 Indexer.updateArticle(
413                     article.getCompanyId(), article.getGroupId(),
414                     article.getArticleId(), article.getVersion(),
415                     article.getTitle(), article.getDescription(),
416                     article.getContent(), article.getType(),
417                     article.getDisplayDate());
418             }
419         }
420         catch (IOException ioe) {
421             _log.error("Indexing " + article.getId(), ioe);
422         }
423 
424         return article;
425     }
426 
427     public JournalArticle checkArticleResourcePrimKey(
428             long groupId, String articleId, double version)
429         throws PortalException, SystemException {
430 
431         JournalArticle article = JournalArticleUtil.findByG_A_V(
432             groupId, articleId, version);
433 
434         if (article.getResourcePrimKey() > 0) {
435             return article;
436         }
437 
438         long resourcePrimKey =
439             JournalArticleResourceLocalServiceUtil.getArticleResourcePrimKey(
440                 groupId, articleId);
441 
442         article.setResourcePrimKey(resourcePrimKey);
443 
444         JournalArticleUtil.update(article);
445 
446         return article;
447     }
448 
449     public void checkArticles() throws PortalException, SystemException {
450         Date now = new Date();
451 
452         List articles = JournalArticleFinder.findByExpirationDate(
453             Boolean.FALSE, now,
454             new Date(now.getTime() - CheckArticleJob.INTERVAL));
455 
456         if (_log.isDebugEnabled()) {
457             _log.debug("Expiring " + articles.size() + " articles");
458         }
459 
460         Set companies = new HashSet();
461 
462         for (int i = 0; i < articles.size(); i++) {
463             JournalArticle article = (JournalArticle)articles.get(i);
464 
465             article.setApproved(false);
466             article.setExpired(true);
467 
468             JournalArticleUtil.update(article);
469 
470             try {
471                 if (article.isIndexable()) {
472                     Indexer.deleteArticle(
473                         article.getCompanyId(), article.getArticleId());
474                 }
475             }
476             catch (IOException ioe) {
477                 _log.error("Removing index " + article.getId(), ioe);
478             }
479 
480             JournalContentUtil.clearCache(
481                 article.getGroupId(), article.getArticleId(),
482                 article.getTemplateId());
483 
484             companies.add(new Long(article.getCompanyId()));
485         }
486 
487         Iterator itr = companies.iterator();
488 
489         while (itr.hasNext()) {
490             long companyId = ((Long)itr.next()).longValue();
491 
492             LayoutCacheUtil.clearCache(companyId);
493         }
494 
495         articles = JournalArticleFinder.findByReviewDate(
496             now, new Date(now.getTime() - CheckArticleJob.INTERVAL));
497 
498         if (_log.isDebugEnabled()) {
499             _log.debug(
500                 "Sending review notifications for " + articles.size() +
501                     " articles");
502         }
503 
504         for (int i = 0; i < articles.size(); i++) {
505             JournalArticle article = (JournalArticle)articles.get(i);
506 
507             Date reviewDate = article.getReviewDate();
508 
509             if (reviewDate != null) {
510                 long diff = reviewDate.getTime() - now.getTime();
511 
512                 if ((diff > 0) && (diff < CheckArticleJob.INTERVAL)) {
513                     String articleURL = StringPool.BLANK;
514 
515                     long ownerId = article.getGroupId();
516                     int ownerType = PortletKeys.PREFS_OWNER_TYPE_GROUP;
517                     long plid = PortletKeys.PREFS_PLID_SHARED;
518                     String portletId = PortletKeys.JOURNAL;
519 
520                     PortletPreferences prefs =
521                         PortletPreferencesLocalServiceUtil.getPreferences(
522                             article.getCompanyId(), ownerId, ownerType, plid,
523                             portletId);
524 
525                     sendEmail(article, articleURL, prefs, "review");
526                 }
527             }
528         }
529     }
530 
531     public void checkNewLine(long groupId, String articleId, double version)
532         throws PortalException, SystemException {
533 
534         JournalArticle article = JournalArticleUtil.findByG_A_V(
535             groupId, articleId, version);
536 
537         String content = article.getContent();
538 
539         if ((content != null) && (content.indexOf("\\n") != -1)) {
540             content = StringUtil.replace(
541                 content,
542                 new String[] {"\\n", "\\r"},
543                 new String[] {"\n", "\r"});
544 
545             article.setContent(content);
546 
547             JournalArticleUtil.update(article);
548         }
549     }
550 
551     public void deleteArticle(
552             long groupId, String articleId, double version, String articleURL,
553             PortletPreferences prefs)
554         throws PortalException, SystemException {
555 
556         JournalArticle article = JournalArticleUtil.findByG_A_V(
557             groupId, articleId, version);
558 
559         deleteArticle(article, articleURL, prefs);
560     }
561 
562     public void deleteArticle(
563             JournalArticle article, String articleURL, PortletPreferences prefs)
564         throws PortalException, SystemException {
565 
566         // Lucene
567 
568         try {
569             if (article.isApproved() && article.isIndexable()) {
570                 Indexer.deleteArticle(
571                     article.getCompanyId(), article.getArticleId());
572             }
573         }
574         catch (IOException ioe) {
575             _log.error("Deleting index " + article.getPrimaryKey(), ioe);
576         }
577 
578         // Email
579 
580         if ((prefs != null) && !article.isApproved() &&
581             isLatestVersion(
582                 article.getGroupId(), article.getArticleId(),
583                 article.getVersion())) {
584 
585             sendEmail(article, articleURL, prefs, "denied");
586         }
587 
588         // Tags
589 
590         TagsAssetLocalServiceUtil.deleteAsset(
591             JournalArticle.class.getName(), article.getResourcePrimKey());
592 
593         // Ratings
594 
595         RatingsStatsLocalServiceUtil.deleteStats(
596             JournalArticle.class.getName(), article.getResourcePrimKey());
597 
598         // Message boards
599 
600         MBMessageLocalServiceUtil.deleteDiscussionMessages(
601             JournalArticle.class.getName(), article.getResourcePrimKey());
602 
603         // Content searches
604 
605         JournalContentSearchLocalServiceUtil.deleteArticleContentSearches(
606             article.getGroupId(), article.getArticleId());
607 
608         // Images
609 
610         JournalArticleImageLocalServiceUtil.deleteImages(
611             article.getGroupId(), article.getArticleId(), article.getVersion());
612 
613         // Resources
614 
615         if (JournalArticleUtil.countByG_A(
616                 article.getGroupId(), article.getArticleId()) == 1) {
617 
618             ResourceLocalServiceUtil.deleteResource(
619                 article.getCompanyId(), JournalArticle.class.getName(),
620                 ResourceImpl.SCOPE_INDIVIDUAL, article.getResourcePrimKey());
621         }
622 
623         // Resource
624 
625         if (JournalArticleUtil.countByG_A(
626                 article.getGroupId(), article.getArticleId()) == 1) {
627 
628             try {
629                 JournalArticleResourceLocalServiceUtil.deleteArticleResource(
630                     article.getGroupId(), article.getArticleId());
631             }
632             catch (NoSuchArticleResourceException nsare) {
633             }
634         }
635 
636         // Article
637 
638         JournalArticleUtil.remove(article.getPrimaryKey());
639     }
640 
641     public void deleteArticles(long groupId)
642         throws PortalException, SystemException {
643 
644         Iterator itr = JournalArticleUtil.findByGroupId(groupId).iterator();
645 
646         while (itr.hasNext()) {
647             JournalArticle article = (JournalArticle)itr.next();
648 
649             deleteArticle(article, null, null);
650         }
651     }
652 
653     public void expireArticle(
654             long groupId, String articleId, double version, String articleURL,
655             PortletPreferences prefs)
656         throws PortalException, SystemException {
657 
658         JournalArticle article = JournalArticleUtil.findByG_A_V(
659             groupId, articleId, version);
660 
661         expireArticle(article, articleURL, prefs);
662     }
663 
664     public void expireArticle(
665             JournalArticle article, String articleURL, PortletPreferences prefs)
666         throws PortalException, SystemException {
667 
668         // Email
669 
670         if ((prefs != null) && !article.isApproved() &&
671             isLatestVersion(
672                 article.getGroupId(), article.getArticleId(),
673                 article.getVersion())) {
674 
675             sendEmail(article, articleURL, prefs, "denied");
676         }
677 
678         // Article
679 
680         article.setExpirationDate(new Date());
681 
682         article.setApproved(false);
683         article.setExpired(true);
684 
685         JournalArticleUtil.update(article);
686 
687         // Lucene
688 
689         try {
690             if (article.isIndexable()) {
691                 Indexer.deleteArticle(
692                     article.getCompanyId(), article.getArticleId());
693             }
694         }
695         catch (IOException ioe) {
696             _log.error("Removing index " + article.getId(), ioe);
697         }
698     }
699 
700     public JournalArticle getArticle(long id)
701         throws PortalException, SystemException {
702 
703         return JournalArticleUtil.findByPrimaryKey(id);
704     }
705 
706     public JournalArticle getArticle(long groupId, String articleId)
707         throws PortalException, SystemException {
708 
709         // Get the latest article that is approved, if none are approved, get
710         // the latest unapproved article
711 
712         try {
713             return getLatestArticle(groupId, articleId, Boolean.TRUE);
714         }
715         catch (NoSuchArticleException nsae) {
716             return getLatestArticle(groupId, articleId, Boolean.FALSE);
717         }
718     }
719 
720     public JournalArticle getArticle(
721             long groupId, String articleId, double version)
722         throws PortalException, SystemException {
723 
724         return JournalArticleUtil.findByG_A_V(groupId, articleId, version);
725     }
726 
727     public String getArticleContent(
728             long groupId, String articleId, String languageId,
729             ThemeDisplay themeDisplay)
730         throws PortalException, SystemException {
731 
732         return getArticleContent(
733             groupId, articleId, null, languageId, themeDisplay);
734     }
735 
736     public String getArticleContent(
737             long groupId, String articleId, String templateId,
738             String languageId, ThemeDisplay themeDisplay)
739         throws PortalException, SystemException {
740 
741         JournalArticleDisplay articleDisplay = getArticleDisplay(
742             groupId, articleId, templateId, languageId, themeDisplay);
743 
744         return articleDisplay.getContent();
745     }
746 
747     public String getArticleContent(
748             long groupId, String articleId, double version, String languageId,
749             ThemeDisplay themeDisplay)
750         throws PortalException, SystemException {
751 
752         return getArticleContent(
753             groupId, articleId, version, null, languageId, themeDisplay);
754     }
755 
756     public String getArticleContent(
757             long groupId, String articleId, double version, String templateId,
758             String languageId, ThemeDisplay themeDisplay)
759         throws PortalException, SystemException {
760 
761         JournalArticleDisplay articleDisplay = getArticleDisplay(
762             groupId, articleId, version, templateId, languageId, themeDisplay);
763 
764         if (articleDisplay == null) {
765             return StringPool.BLANK;
766         }
767         else {
768             return articleDisplay.getContent();
769         }
770     }
771 
772     public JournalArticleDisplay getArticleDisplay(
773             long groupId, String articleId, String languageId,
774             ThemeDisplay themeDisplay)
775         throws PortalException, SystemException {
776 
777         return getArticleDisplay(
778             groupId, articleId, null, languageId, themeDisplay);
779     }
780 
781     public JournalArticleDisplay getArticleDisplay(
782             long groupId, String articleId, String languageId,
783             ThemeDisplay themeDisplay, String xmlRequest)
784         throws PortalException, SystemException {
785 
786         return getArticleDisplay(
787             groupId, articleId, null, languageId, themeDisplay, xmlRequest);
788     }
789 
790     public JournalArticleDisplay getArticleDisplay(
791             long groupId, String articleId, String templateId,
792             String languageId, ThemeDisplay themeDisplay)
793         throws PortalException, SystemException {
794 
795         JournalArticle article = getDisplayArticle(groupId, articleId);
796 
797         return getArticleDisplay(
798             groupId, articleId, article.getVersion(), templateId, languageId,
799             themeDisplay);
800     }
801 
802     public JournalArticleDisplay getArticleDisplay(
803             long groupId, String articleId, String templateId,
804             String languageId, ThemeDisplay themeDisplay, String xmlRequest)
805         throws PortalException, SystemException {
806 
807         JournalArticle article = getDisplayArticle(groupId, articleId);
808 
809         return getArticleDisplay(
810             groupId, articleId, article.getVersion(), templateId, languageId,
811             themeDisplay, xmlRequest);
812     }
813 
814     public JournalArticleDisplay getArticleDisplay(
815             long groupId, String articleId, double version, String templateId,
816             String languageId, ThemeDisplay themeDisplay)
817         throws PortalException, SystemException {
818 
819         return getArticleDisplay(
820             groupId, articleId, version, templateId, languageId, themeDisplay,
821             null);
822     }
823 
824     public JournalArticleDisplay getArticleDisplay(
825             long groupId, String articleId, double version, String templateId,
826             String languageId, ThemeDisplay themeDisplay, String xmlRequest)
827         throws PortalException, SystemException {
828 
829         String content = null;
830 
831         Date now = new Date();
832 
833         JournalArticle article = JournalArticleUtil.findByG_A_V(
834             groupId, articleId, version);
835 
836         if (article.isExpired()) {
837             Date expirationDate = article.getExpirationDate();
838 
839             if ((expirationDate != null) && expirationDate.before(now)) {
840                 return null;
841             }
842         }
843 
844         if (article.getDisplayDate().after(now)) {
845             return null;
846         }
847 
848         /*if (!article.isTemplateDriven()) {
849             return article.getContent();
850         }*/
851 
852         Map tokens = JournalUtil.getTokens(groupId, themeDisplay);
853 
854         String xml = article.getContent();
855 
856         try {
857             Document doc = null;
858 
859             Element root = null;
860 
861             if (article.isTemplateDriven()) {
862                 SAXReader reader = new SAXReader();
863 
864                 doc = reader.read(new StringReader(xml));
865 
866                 root = doc.getRootElement();
867 
868                 if (Validator.isNotNull(xmlRequest)) {
869                     try {
870                         Document request = reader.read(
871                             new StringReader(xmlRequest));
872 
873                         root.add(request.getRootElement().createCopy());
874                     }
875                     catch (Exception e) {
876                     }
877                 }
878 
879                 JournalUtil.addAllReservedEls(root, tokens, article);
880 
881                 xml = JournalUtil.formatXML(doc);
882             }
883         }
884         catch (DocumentException de) {
885             throw new SystemException(de);
886         }
887         catch (IOException ioe) {
888             throw new SystemException(ioe);
889         }
890 
891         try {
892             if (_log.isDebugEnabled()) {
893                 _log.debug(
894                     "Transforming " + articleId + " " + version + " " +
895                         languageId);
896             }
897 
898             String script = null;
899             String langType = null;
900 
901             if (article.isTemplateDriven()) {
902 
903                 // Try with specified template first. If a template is not
904                 // specified, use the default one. If the specified template
905                 // does not exit, use the default one. If the default one does
906                 // not exist, throw an exception.
907 
908                 String defaultTemplateId = article.getTemplateId();
909 
910                 if (Validator.isNull(templateId)) {
911                     templateId = defaultTemplateId;
912                 }
913 
914                 JournalTemplate template = null;
915 
916                 try {
917                     template = JournalTemplateUtil.findByG_T(
918                         groupId, templateId);
919                 }
920                 catch (NoSuchTemplateException nste) {
921                     if (!defaultTemplateId.equals(templateId)) {
922                         template = JournalTemplateUtil.findByG_T(
923                             groupId, defaultTemplateId);
924                     }
925                     else {
926                         throw nste;
927                     }
928                 }
929 
930                 script = template.getXsl();
931                 langType = template.getLangType();
932             }
933 
934             content = JournalUtil.transform(
935                 tokens, languageId, xml, script, langType);
936         }
937         catch (Exception e) {
938             throw new SystemException(e);
939         }
940 
941         return new JournalArticleDisplayImpl(
942             article.getId(), article.getResourcePrimKey(), article.getGroupId(),
943             article.getUserId(), article.getArticleId(), article.getVersion(),
944             article.getTitle(), article.getDescription(),
945             article.getAvailableLocales(), content, article.getType(),
946             article.getStructureId(), templateId);
947     }
948 
949     public List getArticles() throws SystemException {
950         return JournalArticleUtil.findAll();
951     }
952 
953     public List getArticles(long groupId) throws SystemException {
954         return JournalArticleUtil.findByGroupId(groupId);
955     }
956 
957     public List getArticles(long groupId, int begin, int end)
958         throws SystemException {
959 
960         return JournalArticleUtil.findByGroupId(groupId, begin, end);
961     }
962 
963     public List getArticles(
964             long groupId, int begin, int end, OrderByComparator obc)
965         throws SystemException {
966 
967         return JournalArticleUtil.findByGroupId(groupId, begin, end, obc);
968     }
969 
970     public int getArticlesCount(long groupId) throws SystemException {
971         return JournalArticleUtil.countByGroupId(groupId);
972     }
973 
974     public JournalArticle getDisplayArticle(long groupId, String articleId)
975         throws PortalException, SystemException {
976 
977         List articles = JournalArticleUtil.findByG_A_A(
978             groupId, articleId, true);
979 
980         if (articles.size() == 0) {
981             throw new NoSuchArticleException();
982         }
983 
984         Collections.sort(articles, new ArticleDisplayDateComparator());
985 
986         Date now = new Date();
987 
988         for (int i = 0; i < articles.size(); i++) {
989             JournalArticle article = (JournalArticle)articles.get(i);
990 
991             if (article.getDisplayDate().before(now)) {
992                 return article;
993             }
994         }
995 
996         return (JournalArticle)articles.get(0);
997     }
998 
999     public JournalArticle getLatestArticle(long groupId, String articleId)
1000        throws PortalException, SystemException {
1001
1002        return getLatestArticle(groupId, articleId, null);
1003    }
1004
1005    public JournalArticle getLatestArticle(
1006            long groupId, String articleId, Boolean approved)
1007        throws PortalException, SystemException {
1008
1009        List articles = null;
1010
1011        if (approved == null) {
1012            articles = JournalArticleUtil.findByG_A(groupId, articleId, 0, 1);
1013        }
1014        else {
1015            articles = JournalArticleUtil.findByG_A_A(
1016                groupId, articleId, approved.booleanValue(), 0, 1);
1017        }
1018
1019        if (articles.size() == 0) {
1020            throw new NoSuchArticleException();
1021        }
1022
1023        return (JournalArticle)articles.get(0);
1024    }
1025
1026    public double getLatestVersion(long groupId, String articleId)
1027        throws PortalException, SystemException {
1028
1029        JournalArticle article = getLatestArticle(groupId, articleId);
1030
1031        return article.getVersion();
1032    }
1033
1034    public double getLatestVersion(
1035            long groupId, String articleId, Boolean approved)
1036        throws PortalException, SystemException {
1037
1038        JournalArticle article = getLatestArticle(groupId, articleId, approved);
1039
1040        return article.getVersion();
1041    }
1042
1043    public List getStructureArticles(long groupId, String structureId)
1044        throws SystemException {
1045
1046        return JournalArticleUtil.findByG_S(groupId, structureId);
1047    }
1048
1049    public List getStructureArticles(
1050            long groupId, String structureId, int begin, int end,
1051            OrderByComparator obc)
1052        throws SystemException {
1053
1054        return JournalArticleUtil.findByG_S(
1055            groupId, structureId, begin, end, obc);
1056    }
1057
1058    public int getStructureArticlesCount(long groupId, String structureId)
1059        throws SystemException {
1060
1061        return JournalArticleUtil.countByG_S(groupId, structureId);
1062    }
1063
1064    public List getTemplateArticles(long groupId, String templateId)
1065        throws SystemException {
1066
1067        return JournalArticleUtil.findByG_T(groupId, templateId);
1068    }
1069
1070    public List getTemplateArticles(
1071            long groupId, String templateId, int begin, int end,
1072            OrderByComparator obc)
1073        throws SystemException {
1074
1075        return JournalArticleUtil.findByG_T(
1076            groupId, templateId, begin, end, obc);
1077    }
1078
1079    public int getTemplateArticlesCount(long groupId, String templateId)
1080        throws SystemException {
1081
1082        return JournalArticleUtil.countByG_T(groupId, templateId);
1083    }
1084
1085    public boolean hasArticle(long groupId, String articleId)
1086        throws SystemException {
1087
1088        try {
1089            getArticle(groupId, articleId);
1090
1091            return true;
1092        }
1093        catch (PortalException pe) {
1094            return false;
1095        }
1096    }
1097
1098    public boolean isLatestVersion(
1099            long groupId, String articleId, double version)
1100        throws PortalException, SystemException {
1101
1102        if (getLatestVersion(groupId, articleId) == version) {
1103            return true;
1104        }
1105        else {
1106            return false;
1107        }
1108    }
1109
1110    public boolean isLatestVersion(
1111            long groupId, String articleId, double version, Boolean active)
1112        throws PortalException, SystemException {
1113
1114        if (getLatestVersion(groupId, articleId, active) == version) {
1115            return true;
1116        }
1117        else {
1118            return false;
1119        }
1120    }
1121
1122    public void reIndex(String[] ids) throws SystemException {
1123        long companyId = GetterUtil.getLong(ids[0]);
1124
1125        IndexWriter writer = null;
1126
1127        try {
1128            writer = LuceneUtil.getWriter(companyId);
1129
1130            Iterator itr = JournalArticleUtil.findByCompanyId(
1131                companyId).iterator();
1132
1133            while (itr.hasNext()) {
1134                JournalArticle article = (JournalArticle)itr.next();
1135
1136                long groupId = article.getGroupId();
1137                String articleId = article.getArticleId();
1138                double version = article.getVersion();
1139                String title = article.getTitle();
1140                String description = article.getDescription();
1141                String content = article.getContent();
1142                String type = article.getType();
1143                Date displayDate = article.getDisplayDate();
1144
1145                if (article.isApproved() && article.isIndexable()) {
1146                    try {
1147                        org.apache.lucene.document.Document doc =
1148                            Indexer.getAddArticleDocument(
1149                                companyId, groupId, articleId, version, title,
1150                                description, content, type, displayDate);
1151
1152                        writer.addDocument(doc);
1153                    }
1154                    catch (Exception e1) {
1155                        _log.error("Reindexing " + article.getId(), e1);
1156                    }
1157                }
1158            }
1159        }
1160        catch (SystemException se) {
1161            throw se;
1162        }
1163        catch (Exception e2) {
1164            throw new SystemException(e2);
1165        }
1166        finally {
1167            try {
1168                if (writer != null) {
1169                    LuceneUtil.write(companyId);
1170                }
1171            }
1172            catch (Exception e) {
1173                _log.error(e);
1174            }
1175        }
1176    }
1177
1178    public JournalArticle removeArticleLocale(
1179            long groupId, String articleId, double version, String languageId)
1180        throws PortalException, SystemException {
1181
1182        JournalArticle article = JournalArticleUtil.findByG_A_V(
1183            groupId, articleId, version);
1184
1185        String content = article.getContent();
1186
1187        if (article.isTemplateDriven()) {
1188            content = JournalUtil.removeArticleLocale(content, languageId);
1189        }
1190        else {
1191            content = LocalizationUtil.removeLocalization(
1192                content, "static-content", languageId);
1193        }
1194
1195        article.setContent(content);
1196
1197        JournalArticleUtil.update(article);
1198
1199        return article;
1200    }
1201
1202    public Hits search(
1203            long companyId, long groupId, String title, String description,
1204            String content, String type)
1205        throws SystemException {
1206
1207        return search(
1208            companyId, groupId, title, description, content, type,
1209            "displayDate");
1210    }
1211
1212    public Hits search(
1213            long companyId, long groupId, String title, String description,
1214            String content, String type, String sortField)
1215        throws SystemException {
1216
1217        Searcher searcher = null;
1218
1219        try {
1220            HitsImpl hits = new HitsImpl();
1221
1222            if ((Validator.isNull(title)) && (Validator.isNull(content)) &&
1223                (Validator.isNull(type))) {
1224
1225                return hits;
1226            }
1227
1228            BooleanQuery contextQuery = new BooleanQuery();
1229
1230            LuceneUtil.addRequiredTerm(
1231                contextQuery, LuceneFields.PORTLET_ID, Indexer.PORTLET_ID);
1232
1233            if (groupId > 0) {
1234                LuceneUtil.addRequiredTerm(
1235                    contextQuery, LuceneFields.GROUP_ID, groupId);
1236            }
1237
1238            BooleanQuery searchQuery = new BooleanQuery();
1239
1240            LuceneUtil.addTerm(searchQuery, LuceneFields.TITLE, title);
1241            LuceneUtil.addTerm(searchQuery, LuceneFields.CONTENT, content);
1242            LuceneUtil.addTerm(
1243                searchQuery, LuceneFields.DESCRIPTION, description);
1244
1245            if (Validator.isNotNull(type)) {
1246                LuceneUtil.addRequiredTerm(searchQuery, "type", type);
1247            }
1248
1249            BooleanQuery fullQuery = new BooleanQuery();
1250
1251            fullQuery.add(contextQuery, BooleanClause.Occur.MUST);
1252            fullQuery.add(searchQuery, BooleanClause.Occur.MUST);
1253
1254            searcher = LuceneUtil.getSearcher(companyId);
1255
1256            Sort sort = new Sort(new SortField(sortField, true));
1257
1258            try {
1259                hits.recordHits(searcher.search(fullQuery, sort), searcher);
1260            }
1261            catch (RuntimeException re) {
1262
1263                // Trying to sort on a field when there are no results throws a
1264                // RuntimeException that should not be rethrown
1265
1266                String msg = GetterUtil.getString(re.getMessage());
1267
1268                if (!msg.endsWith("does not appear to be indexed")) {
1269                    throw re;
1270                }
1271            }
1272
1273            return hits;
1274        }
1275        catch (Exception e) {
1276            StringMaker sm = new StringMaker();
1277
1278            sm.append(title);
1279            sm.append(StringPool.SPACE);
1280            sm.append(content);
1281            sm.append(StringPool.SPACE);
1282            sm.append(description);
1283
1284            String keywords = sm.toString();
1285
1286            return LuceneUtil.closeSearcher(searcher, keywords, e);
1287        }
1288    }
1289
1290    public List search(
1291            long companyId, long groupId, String keywords, Double version,
1292            String type, String structureId, String templateId,
1293            Date displayDateGT, Date displayDateLT, Boolean approved,
1294            Boolean expired, Date reviewDate, int begin, int end,
1295            OrderByComparator obc)
1296        throws SystemException {
1297
1298        return JournalArticleFinder.findByKeywords(
1299            companyId, groupId, keywords, version, type, structureId,
1300            templateId, displayDateGT, displayDateLT, approved, expired,
1301            reviewDate, begin, end, obc);
1302    }
1303
1304    public List search(
1305            long companyId, long groupId, String articleId, Double version,
1306            String title, String description, String content, String type,
1307            String structureId, String templateId, Date displayDateGT,
1308            Date displayDateLT, Boolean approved, Boolean expired,
1309            Date reviewDate, boolean andOperator, int begin, int end,
1310            OrderByComparator obc)
1311        throws SystemException {
1312
1313        return JournalArticleFinder.findByC_G_A_V_T_D_C_T_S_T_D_A_E_R(
1314            companyId, groupId, articleId, version, title, description, content,
1315            type, structureId, templateId, displayDateGT, displayDateLT,
1316            approved, expired, reviewDate, andOperator, begin, end, obc);
1317    }
1318
1319    public List search(
1320            long companyId, long groupId, String articleId, Double version,
1321            String title, String description, String content, String type,
1322            String[] structureIds, String[] templateIds, Date displayDateGT,
1323            Date displayDateLT, Boolean approved, Boolean expired,
1324            Date reviewDate, boolean andOperator, int begin, int end,
1325            OrderByComparator obc)
1326        throws SystemException {
1327
1328        return JournalArticleFinder.findByC_G_A_V_T_D_C_T_S_T_D_A_E_R(
1329            companyId, groupId, articleId, version, title, description, content,
1330            type, structureIds, templateIds, displayDateGT, displayDateLT,
1331            approved, expired, reviewDate, andOperator, begin, end, obc);
1332    }
1333
1334    public int searchCount(
1335            long companyId, long groupId, String keywords, Double version,
1336            String type, String structureId, String templateId,
1337            Date displayDateGT, Date displayDateLT, Boolean approved,
1338            Boolean expired, Date reviewDate)
1339        throws SystemException {
1340
1341        return JournalArticleFinder.countByKeywords(
1342            companyId, groupId, keywords, version, type, structureId,
1343            templateId, displayDateGT, displayDateLT, approved, expired,
1344            reviewDate);
1345    }
1346
1347    public int searchCount(
1348            long companyId, long groupId, String articleId, Double version,
1349            String title, String description, String content, String type,
1350            String structureId, String templateId, Date displayDateGT,
1351            Date displayDateLT, Boolean approved, Boolean expired,
1352            Date reviewDate, boolean andOperator)
1353        throws SystemException {
1354
1355        return JournalArticleFinder.countByC_G_A_V_T_D_C_T_S_T_D_A_E_R(
1356            companyId, groupId, articleId, version, title, description, content,
1357            type, structureId, templateId, displayDateGT, displayDateLT,
1358            approved, expired, reviewDate, andOperator);
1359    }
1360
1361    public int searchCount(
1362            long companyId, long groupId, String articleId, Double version,
1363            String title, String description, String content, String type,
1364            String[] structureIds, String[] templateIds, Date displayDateGT,
1365            Date displayDateLT, Boolean approved, Boolean expired,
1366            Date reviewDate, boolean andOperator)
1367        throws SystemException {
1368
1369        return JournalArticleFinder.countByC_G_A_V_T_D_C_T_S_T_D_A_E_R(
1370            companyId, groupId, articleId, version, title, description, content,
1371            type, structureIds, templateIds, displayDateGT, displayDateLT,
1372            approved, expired, reviewDate, andOperator);
1373    }
1374
1375    public JournalArticle updateArticle(
1376            long userId, long groupId, String articleId, double version,
1377            boolean incrementVersion, String title, String description,
1378            String content, String type, String structureId, String templateId,
1379            int displayDateMonth, int displayDateDay, int displayDateYear,
1380            int displayDateHour, int displayDateMinute, int expirationDateMonth,
1381            int expirationDateDay, int expirationDateYear,
1382            int expirationDateHour, int expirationDateMinute,
1383            boolean neverExpire, int reviewDateMonth, int reviewDateDay,
1384            int reviewDateYear, int reviewDateHour, int reviewDateMinute,
1385            boolean neverReview, boolean indexable, Map images,
1386            String articleURL, PortletPreferences prefs, String[] tagsEntries)
1387        throws PortalException, SystemException {
1388
1389        // Article
1390
1391        User user = UserUtil.findByPrimaryKey(userId);
1392        articleId = articleId.trim().toUpperCase();
1393        Date now = new Date();
1394
1395        Date displayDate = PortalUtil.getDate(
1396            displayDateMonth, displayDateDay, displayDateYear,
1397            displayDateHour, displayDateMinute, user.getTimeZone(),
1398            new ArticleDisplayDateException());
1399
1400        Date expirationDate = null;
1401
1402        if (!neverExpire) {
1403            expirationDate = PortalUtil.getDate(
1404                expirationDateMonth, expirationDateDay, expirationDateYear,
1405                expirationDateHour, expirationDateMinute, user.getTimeZone(),
1406                new ArticleExpirationDateException());
1407        }
1408
1409        Date reviewDate = null;
1410
1411        if (!neverReview) {
1412            reviewDate = PortalUtil.getDate(
1413                reviewDateMonth, reviewDateDay, reviewDateYear, reviewDateHour,
1414                reviewDateMinute, user.getTimeZone(),
1415                new ArticleReviewDateException());
1416        }
1417
1418        validate(groupId, title, content, type, structureId, templateId);
1419
1420        JournalArticle oldArticle = JournalArticleUtil.findByG_A_V(
1421            groupId, articleId, version);
1422
1423        JournalArticle article = null;
1424
1425        if (incrementVersion) {
1426            double latestVersion = getLatestVersion(groupId, articleId);
1427
1428            long id = CounterLocalServiceUtil.increment();
1429
1430            article = JournalArticleUtil.create(id);
1431
1432            article.setResourcePrimKey(oldArticle.getResourcePrimKey());
1433            article.setGroupId(oldArticle.getGroupId());
1434            article.setCompanyId(user.getCompanyId());
1435            article.setUserId(user.getUserId());
1436            article.setUserName(user.getFullName());
1437            article.setCreateDate(now);
1438            article.setArticleId(articleId);
1439            article.setVersion(MathUtil.format(latestVersion + 0.1, 1, 1));
1440        }
1441        else {
1442            article = oldArticle;
1443        }
1444
1445        content = format(
1446            groupId, articleId, article.getVersion(), incrementVersion, content,
1447            structureId, images);
1448
1449        boolean approved = oldArticle.isApproved();
1450
1451        if (incrementVersion) {
1452            approved = false;
1453        }
1454
1455        article.setModifiedDate(now);
1456        article.setTitle(title);
1457        article.setDescription(description);
1458        article.setContent(content);
1459        article.setType(type);
1460        article.setStructureId(structureId);
1461        article.setTemplateId(templateId);
1462        article.setDisplayDate(displayDate);
1463        article.setApproved(approved);
1464
1465        if ((expirationDate == null) || expirationDate.after(now)) {
1466            article.setExpired(false);
1467        }
1468        else {
1469            article.setExpired(true);
1470        }
1471
1472        article.setExpirationDate(expirationDate);
1473        article.setReviewDate(reviewDate);
1474        article.setIndexable(indexable);
1475
1476        JournalArticleUtil.update(article);
1477
1478        // Tags
1479
1480        updateTagsAsset(userId, article, tagsEntries);
1481
1482        // Email
1483
1484        if (incrementVersion) {
1485            sendEmail(article, articleURL, prefs, "requested");
1486        }
1487
1488        // Lucene
1489
1490        try {
1491            if (article.isIndexable()) {
1492                if (article.isApproved()) {
1493                    Indexer.updateArticle(
1494                        article.getCompanyId(), article.getGroupId(),
1495                        article.getArticleId(), article.getVersion(),
1496                        article.getTitle(), article.getDescription(),
1497                        article.getContent(), article.getType(),
1498                        article.getDisplayDate());
1499                }
1500                else {
1501                    Indexer.deleteArticle(
1502                        article.getCompanyId(), article.getArticleId());
1503                }
1504            }
1505        }
1506        catch (IOException ioe) {
1507            _log.error("Indexing " + article.getPrimaryKey(), ioe);
1508        }
1509
1510        return article;
1511    }
1512
1513    public JournalArticle updateContent(
1514            long groupId, String articleId, double version, String content)
1515        throws PortalException, SystemException {
1516
1517        JournalArticle article = JournalArticleUtil.findByG_A_V(
1518            groupId, articleId, version);
1519
1520        article.setContent(content);
1521
1522        JournalArticleUtil.update(article);
1523
1524        return article;
1525    }
1526
1527    public void updateTagsAsset(
1528            long userId, JournalArticle article, String[] tagsEntries)
1529        throws PortalException, SystemException {
1530
1531        boolean updateAsset = true;
1532
1533        if (article.getVersion() == 1) {
1534        }
1535        else if (!article.isApproved()) {
1536            updateAsset = false;
1537        }
1538        else if (!isLatestVersion(
1539                    article.getGroupId(), article.getArticleId(),
1540                    article.getVersion(), Boolean.TRUE)) {
1541
1542                updateAsset = false;
1543        }
1544
1545        if (updateAsset) {
1546            TagsAssetLocalServiceUtil.updateAsset(
1547                userId, JournalArticle.class.getName(),
1548                article.getResourcePrimKey(), tagsEntries, null, null,
1549                article.getDisplayDate(), article.getExpirationDate(),
1550                ContentTypes.TEXT_HTML, article.getTitle(),
1551                article.getDescription(), article.getDescription(), null, 0, 0);
1552        }
1553    }
1554
1555    protected String format(
1556            long groupId, String articleId, double version,
1557            boolean incrementVersion, String content, String structureId,
1558            Map images)
1559        throws SystemException {
1560
1561        if (Validator.isNotNull(structureId)) {
1562            SAXReader reader = new SAXReader();
1563
1564            Document doc = null;
1565
1566            try {
1567                doc = reader.read(new StringReader(content));
1568
1569                Element root = doc.getRootElement();
1570
1571                format(
1572                    groupId, articleId, version, incrementVersion,
1573                    root, images);
1574
1575                content = JournalUtil.formatXML(doc);
1576            }
1577            catch (DocumentException de) {
1578                _log.error(de);
1579            }
1580            catch (IOException ioe) {
1581                _log.error(ioe);
1582            }
1583        }
1584
1585        return content;
1586    }
1587
1588    protected void format(
1589            long groupId, String articleId, double version,
1590            boolean incrementVersion, Element root, Map images)
1591        throws SystemException {
1592
1593        Iterator itr = root.elements().iterator();
1594
1595        while (itr.hasNext()) {
1596            Element el = (Element)itr.next();
1597
1598            String elName = el.attributeValue("name", StringPool.BLANK);
1599            String elType = el.attributeValue("type", StringPool.BLANK);
1600
1601            if (elType.equals("image")) {
1602                formatImage(
1603                    groupId, articleId, version, incrementVersion, el, elName,
1604                    images);
1605            }
1606            else if (elType.equals("text_area")) {
1607                Element dynamicContent = el.element("dynamic-content");
1608
1609                String text = dynamicContent.getText();
1610
1611                // LEP-1594
1612
1613                try {
1614                    text = ParserUtils.trimTags(
1615                        text, new String[] {"script"}, false, true);
1616                }
1617                catch (ParserException pe) {
1618                    text = pe.getLocalizedMessage();
1619                }
1620                catch (UnsupportedEncodingException uee) {
1621                    text = uee.getLocalizedMessage();
1622                }
1623
1624                dynamicContent.setText(text);
1625            }
1626
1627            format(
1628                groupId, articleId, version, incrementVersion, el, images);
1629        }
1630    }
1631
1632    protected void formatImage(
1633            long groupId, String articleId, double version,
1634            boolean incrementVersion, Element el, String elName, Map images)
1635        throws SystemException {
1636
1637        List imageContents = el.elements("dynamic-content");
1638
1639        Iterator itr = imageContents.listIterator();
1640
1641        while (itr.hasNext()) {
1642            Element dynamicContent = (Element)itr.next();
1643
1644            String elLanguage = dynamicContent.attributeValue(
1645                "language-id", StringPool.BLANK);
1646
1647            if (!elLanguage.equals(StringPool.BLANK)) {
1648                elLanguage = "_" + elLanguage;
1649            }
1650
1651            long imageId =
1652                JournalArticleImageLocalServiceUtil.getArticleImageId(
1653                    groupId, articleId, version, elName, elLanguage);
1654
1655            double oldVersion = MathUtil.format(version - 0.1, 1, 1);
1656
1657            long oldImageId = 0;
1658
1659            if (oldVersion >= 1) {
1660                oldImageId =
1661                    JournalArticleImageLocalServiceUtil.getArticleImageId(
1662                        groupId, articleId, oldVersion, elName, elLanguage);
1663            }
1664
1665            String elContent =
1666                "/image/journal/article?img_id=" + imageId + "&t=" +
1667                    ImageServletTokenUtil.getToken(imageId);
1668
1669            if (dynamicContent.getText().equals("delete")) {
1670                dynamicContent.setText(StringPool.BLANK);
1671
1672                ImageLocalUtil.deleteImage(imageId);
1673
1674                String defaultElLanguage = "";
1675
1676                if (!Validator.isNotNull(elLanguage)) {
1677                    defaultElLanguage =
1678                        "_" + LocaleUtil.toLanguageId(LocaleUtil.getDefault());
1679                }
1680
1681                long defaultImageId =
1682                    JournalArticleImageLocalServiceUtil.getArticleImageId(
1683                        groupId, articleId, version, elName, defaultElLanguage);
1684
1685                ImageLocalUtil.deleteImage(defaultImageId);
1686
1687                continue;
1688            }
1689
1690            byte[] bytes = (byte[])images.get(elName + elLanguage);
1691
1692            if (bytes != null && (bytes.length > 0)) {
1693                dynamicContent.setText(elContent);
1694                dynamicContent.addAttribute("id", String.valueOf(imageId));
1695
1696                ImageLocalUtil.updateImage(imageId, bytes);
1697
1698                continue;
1699            }
1700
1701            if ((version > JournalArticleImpl.DEFAULT_VERSION) &&
1702                (incrementVersion)) {
1703
1704                Image oldImage = null;
1705
1706                if (oldImageId > 0) {
1707                    oldImage = ImageLocalUtil.getImage(oldImageId);
1708                }
1709
1710                if (oldImage != null) {
1711                    dynamicContent.setText(elContent);
1712                    dynamicContent.addAttribute("id", String.valueOf(imageId));
1713
1714                    bytes = oldImage.getTextObj();
1715
1716                    ImageLocalUtil.updateImage(imageId, bytes);
1717                }
1718
1719                continue;
1720            }
1721
1722            Image image = ImageLocalUtil.getImage(imageId);
1723
1724            if (image != null) {
1725                dynamicContent.setText(elContent);
1726                dynamicContent.addAttribute("id", String.valueOf(imageId));
1727
1728                continue;
1729            }
1730
1731            String defaultElLanguage = "";
1732
1733            if (!Validator.isNotNull(elLanguage)) {
1734                defaultElLanguage =
1735                    "_" + LocaleUtil.toLanguageId(LocaleUtil.getDefault());
1736            }
1737
1738            long defaultImageId =
1739                JournalArticleImageLocalServiceUtil.getArticleImageId(
1740                    groupId, articleId, version, elName, defaultElLanguage);
1741
1742            Image defaultImage = ImageLocalUtil.getImage(defaultImageId);
1743
1744            if (defaultImage != null) {
1745                dynamicContent.setText(elContent);
1746                dynamicContent.addAttribute("id", String.valueOf(imageId));
1747
1748                bytes = defaultImage.getTextObj();
1749
1750                ImageLocalUtil.updateImage(imageId, bytes);
1751
1752                continue;
1753            }
1754
1755            dynamicContent.setText(StringPool.BLANK);
1756        }
1757    }
1758
1759    protected void sendEmail(
1760            JournalArticle article, String articleURL, PortletPreferences prefs,
1761            String emailType)
1762        throws PortalException, SystemException {
1763
1764        try {
1765            if (emailType.equals("denied") &&
1766                JournalUtil.getEmailArticleApprovalDeniedEnabled(prefs)) {
1767            }
1768            else if (emailType.equals("granted") &&
1769                     JournalUtil.getEmailArticleApprovalGrantedEnabled(prefs)) {
1770            }
1771            else if (emailType.equals("requested") &&
1772                     JournalUtil.getEmailArticleApprovalRequestedEnabled(
1773                        prefs)) {
1774            }
1775            else if (emailType.equals("review") &&
1776                     JournalUtil.getEmailArticleReviewEnabled(prefs)) {
1777            }
1778            else {
1779                return;
1780            }
1781
1782            Company company = CompanyUtil.findByPrimaryKey(
1783                article.getCompanyId());
1784
1785            User user = UserUtil.findByPrimaryKey(article.getUserId());
1786
1787            articleURL +=
1788                "&groupId=" + article.getGroupId() + "&articleId=" +
1789                    article.getArticleId() + "&version=" + article.getVersion();
1790
1791            String portletName = PortalUtil.getPortletTitle(
1792                PortletKeys.JOURNAL, user);
1793
1794            String fromName = JournalUtil.getEmailFromName(prefs);
1795            String fromAddress = JournalUtil.getEmailFromAddress(prefs);
1796
1797            String toName = user.getFullName();
1798            String toAddress = user.getEmailAddress();
1799
1800            if (emailType.equals("requested") ||
1801                emailType.equals("review")) {
1802
1803                String tempToName = fromName;
1804                String tempToAddress = fromAddress;
1805
1806                fromName = toName;
1807                fromAddress = toAddress;
1808
1809                toName = tempToName;
1810                toAddress = tempToAddress;
1811            }
1812
1813            String subject = null;
1814            String body = null;
1815
1816            if (emailType.equals("denied")) {
1817                subject =
1818                    JournalUtil.getEmailArticleApprovalDeniedSubject(prefs);
1819                body = JournalUtil.getEmailArticleApprovalDeniedBody(prefs);
1820            }
1821            else if (emailType.equals("granted")) {
1822                subject =
1823                    JournalUtil.getEmailArticleApprovalGrantedSubject(prefs);
1824                body = JournalUtil.getEmailArticleApprovalGrantedBody(prefs);
1825            }
1826            else if (emailType.equals("requested")) {
1827                subject =
1828                    JournalUtil.getEmailArticleApprovalRequestedSubject(prefs);
1829                body = JournalUtil.getEmailArticleApprovalRequestedBody(prefs);
1830            }
1831            else if (emailType.equals("review")) {
1832                subject = JournalUtil.getEmailArticleReviewSubject(prefs);
1833                body = JournalUtil.getEmailArticleReviewBody(prefs);
1834            }
1835
1836            subject = StringUtil.replace(
1837                subject,
1838                new String[] {
1839                    "[$ARTICLE_ID$]",
1840                    "[$ARTICLE_TITLE$]",
1841                    "[$ARTICLE_URL$]",
1842                    "[$ARTICLE_VERSION$]",
1843                    "[$FROM_ADDRESS$]",
1844                    "[$FROM_NAME$]",
1845                    "[$PORTAL_URL$]",
1846                    "[$PORTLET_NAME$]",
1847                    "[$TO_ADDRESS$]",
1848                    "[$TO_NAME$]"
1849                },
1850                new String[] {
1851                    article.getArticleId(),
1852                    article.getTitle(),
1853                    articleURL,
1854                    String.valueOf(article.getVersion()),
1855                    fromAddress,
1856                    fromName,
1857                    company.getVirtualHost(),
1858                    portletName,
1859                    toAddress,
1860                    toName,
1861                });
1862
1863            body = StringUtil.replace(
1864                body,
1865                new String[] {
1866                    "[$ARTICLE_ID$]",
1867                    "[$ARTICLE_TITLE$]",
1868                    "[$ARTICLE_URL$]",
1869                    "[$ARTICLE_VERSION$]",
1870                    "[$FROM_ADDRESS$]",
1871                    "[$FROM_NAME$]",
1872                    "[$PORTAL_URL$]",
1873                    "[$PORTLET_NAME$]",
1874                    "[$TO_ADDRESS$]",
1875                    "[$TO_NAME$]"
1876                },
1877                new String[] {
1878                    article.getArticleId(),
1879                    article.getTitle(),
1880                    articleURL,
1881                    String.valueOf(article.getVersion()),
1882                    fromAddress,
1883                    fromName,
1884                    company.getVirtualHost(),
1885                    portletName,
1886                    toAddress,
1887                    toName,
1888                });
1889
1890            InternetAddress from = new InternetAddress(fromAddress, fromName);
1891
1892            InternetAddress to = new InternetAddress(toAddress, toName);
1893
1894            MailMessage message = new MailMessage(
1895                from, to, subject, body, true);
1896
1897            MailServiceUtil.sendEmail(message);
1898        }
1899        catch (IOException ioe) {
1900            throw new SystemException(ioe);
1901        }
1902        catch (PortalException pe) {
1903            throw pe;
1904        }
1905    }
1906
1907    protected void validate(
1908            long groupId, String articleId, boolean autoArticleId, String title,
1909            String content, String type, String structureId, String templateId)
1910        throws PortalException, SystemException {
1911
1912        if (!autoArticleId) {
1913            if ((Validator.isNull(articleId)) ||
1914                (Validator.isNumber(articleId)) ||
1915                (articleId.indexOf(StringPool.SPACE) != -1)) {
1916
1917                throw new ArticleIdException();
1918            }
1919
1920            try {
1921                JournalArticleUtil.findByG_A_V(
1922                    groupId, articleId, JournalArticleImpl.DEFAULT_VERSION);
1923
1924                throw new DuplicateArticleIdException();
1925            }
1926            catch (NoSuchArticleException nste) {
1927            }
1928        }
1929
1930        validate(groupId, title, content, type, structureId, templateId);
1931    }
1932
1933    protected void validate(
1934            long groupId, String title, String content, String type,
1935            String structureId, String templateId)
1936        throws PortalException, SystemException {
1937
1938        if (Validator.isNull(title)) {
1939            throw new ArticleTitleException();
1940        }
1941        else if (Validator.isNull(content)) {
1942            throw new ArticleContentException();
1943        }
1944        else if (Validator.isNull(type)) {
1945            throw new ArticleTypeException();
1946        }
1947
1948        if (Validator.isNotNull(structureId)) {
1949            JournalStructureUtil.findByG_S(groupId, structureId);
1950
1951            JournalTemplate template = JournalTemplateUtil.findByG_T(
1952                groupId, templateId);
1953
1954            if (!template.getStructureId().equals(structureId)) {
1955                throw new NoSuchTemplateException();
1956            }
1957        }
1958    }
1959
1960    private static Log _log =
1961        LogFactory.getLog(JournalArticleLocalServiceImpl.class);
1962
1963}