1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * The contents of this file are subject to the terms of the Liferay Enterprise
5    * Subscription License ("License"). You may not use this file except in
6    * compliance with the License. You can obtain a copy of the License by
7    * contacting Liferay, Inc. See the License for the specific language governing
8    * permissions and limitations under the License, including but not limited to
9    * distribution rights of the Software.
10   *
11   *
12   * 
13   */
14  
15  package com.liferay.portlet.journal.service.impl;
16  
17  import com.liferay.portal.NoSuchImageException;
18  import com.liferay.portal.PortalException;
19  import com.liferay.portal.SystemException;
20  import com.liferay.portal.kernel.log.Log;
21  import com.liferay.portal.kernel.log.LogFactoryUtil;
22  import com.liferay.portal.kernel.mail.MailMessage;
23  import com.liferay.portal.kernel.search.BooleanClause;
24  import com.liferay.portal.kernel.search.BooleanClauseOccur;
25  import com.liferay.portal.kernel.search.BooleanQuery;
26  import com.liferay.portal.kernel.search.BooleanQueryFactoryUtil;
27  import com.liferay.portal.kernel.search.Field;
28  import com.liferay.portal.kernel.search.Hits;
29  import com.liferay.portal.kernel.search.SearchEngineUtil;
30  import com.liferay.portal.kernel.search.SearchException;
31  import com.liferay.portal.kernel.search.Sort;
32  import com.liferay.portal.kernel.servlet.ImageServletTokenUtil;
33  import com.liferay.portal.kernel.util.CalendarFactoryUtil;
34  import com.liferay.portal.kernel.util.ContentTypes;
35  import com.liferay.portal.kernel.util.FileUtil;
36  import com.liferay.portal.kernel.util.GetterUtil;
37  import com.liferay.portal.kernel.util.HtmlUtil;
38  import com.liferay.portal.kernel.util.HttpUtil;
39  import com.liferay.portal.kernel.util.ListUtil;
40  import com.liferay.portal.kernel.util.LocaleUtil;
41  import com.liferay.portal.kernel.util.LocalizationUtil;
42  import com.liferay.portal.kernel.util.MathUtil;
43  import com.liferay.portal.kernel.util.OrderByComparator;
44  import com.liferay.portal.kernel.util.PropsKeys;
45  import com.liferay.portal.kernel.util.StringPool;
46  import com.liferay.portal.kernel.util.StringUtil;
47  import com.liferay.portal.kernel.util.Validator;
48  import com.liferay.portal.kernel.xml.Document;
49  import com.liferay.portal.kernel.xml.DocumentException;
50  import com.liferay.portal.kernel.xml.Element;
51  import com.liferay.portal.kernel.xml.Node;
52  import com.liferay.portal.kernel.xml.SAXReaderUtil;
53  import com.liferay.portal.kernel.xml.XPath;
54  import com.liferay.portal.model.Company;
55  import com.liferay.portal.model.Image;
56  import com.liferay.portal.model.PortletPreferencesIds;
57  import com.liferay.portal.model.ResourceConstants;
58  import com.liferay.portal.model.User;
59  import com.liferay.portal.service.ServiceContext;
60  import com.liferay.portal.service.ServiceContextUtil;
61  import com.liferay.portal.servlet.filters.cache.CacheUtil;
62  import com.liferay.portal.theme.ThemeDisplay;
63  import com.liferay.portal.util.PortalUtil;
64  import com.liferay.portal.util.PortletKeys;
65  import com.liferay.portal.util.PrefsPropsUtil;
66  import com.liferay.portal.util.PropsUtil;
67  import com.liferay.portal.util.PropsValues;
68  import com.liferay.portlet.expando.model.ExpandoBridge;
69  import com.liferay.portlet.journal.ArticleContentException;
70  import com.liferay.portlet.journal.ArticleDisplayDateException;
71  import com.liferay.portlet.journal.ArticleExpirationDateException;
72  import com.liferay.portlet.journal.ArticleIdException;
73  import com.liferay.portlet.journal.ArticleReviewDateException;
74  import com.liferay.portlet.journal.ArticleSmallImageNameException;
75  import com.liferay.portlet.journal.ArticleSmallImageSizeException;
76  import com.liferay.portlet.journal.ArticleTitleException;
77  import com.liferay.portlet.journal.ArticleTypeException;
78  import com.liferay.portlet.journal.DuplicateArticleIdException;
79  import com.liferay.portlet.journal.NoSuchArticleException;
80  import com.liferay.portlet.journal.NoSuchArticleResourceException;
81  import com.liferay.portlet.journal.NoSuchTemplateException;
82  import com.liferay.portlet.journal.StructureXsdException;
83  import com.liferay.portlet.journal.job.CheckArticleJob;
84  import com.liferay.portlet.journal.model.JournalArticle;
85  import com.liferay.portlet.journal.model.JournalArticleDisplay;
86  import com.liferay.portlet.journal.model.JournalStructure;
87  import com.liferay.portlet.journal.model.JournalTemplate;
88  import com.liferay.portlet.journal.model.impl.JournalArticleDisplayImpl;
89  import com.liferay.portlet.journal.model.impl.JournalArticleImpl;
90  import com.liferay.portlet.journal.service.base.JournalArticleLocalServiceBaseImpl;
91  import com.liferay.portlet.journal.util.Indexer;
92  import com.liferay.portlet.journal.util.JournalUtil;
93  import com.liferay.portlet.journal.util.comparator.ArticleIDComparator;
94  import com.liferay.portlet.journal.util.comparator.ArticleVersionComparator;
95  import com.liferay.portlet.journalcontent.util.JournalContentUtil;
96  import com.liferay.portlet.tags.model.TagsEntry;
97  import com.liferay.portlet.tags.model.TagsEntryConstants;
98  
99  import java.io.File;
100 import java.io.IOException;
101 
102 import java.util.Calendar;
103 import java.util.Date;
104 import java.util.HashSet;
105 import java.util.List;
106 import java.util.Map;
107 import java.util.Set;
108 
109 import javax.mail.internet.InternetAddress;
110 
111 import javax.portlet.PortletPreferences;
112 
113 /**
114  * <a href="JournalArticleLocalServiceImpl.java.html"><b><i>View Source</i></b>
115  * </a>
116  *
117  * @author Brian Wing Shun Chan
118  * @author Raymond Augé
119  * @author Bruno Farache
120  */
121 public class JournalArticleLocalServiceImpl
122     extends JournalArticleLocalServiceBaseImpl {
123 
124     public JournalArticle addArticle(
125             long userId, long groupId, String articleId, boolean autoArticleId,
126             double version, String title, String description, String content,
127             String type, String structureId, String templateId,
128             int displayDateMonth, int displayDateDay, int displayDateYear,
129             int displayDateHour, int displayDateMinute, int expirationDateMonth,
130             int expirationDateDay, int expirationDateYear,
131             int expirationDateHour, int expirationDateMinute,
132             boolean neverExpire, int reviewDateMonth, int reviewDateDay,
133             int reviewDateYear, int reviewDateHour, int reviewDateMinute,
134             boolean neverReview, boolean indexable, boolean smallImage,
135             String smallImageURL, File smallFile, Map<String, byte[]> images,
136             String articleURL, ServiceContext serviceContext)
137         throws PortalException, SystemException {
138 
139         return addArticle(
140             null, userId, groupId, articleId, autoArticleId, version, title,
141             description, content, type, structureId, templateId,
142             displayDateMonth, displayDateDay, displayDateYear, displayDateHour,
143             displayDateMinute, expirationDateMonth, expirationDateDay,
144             expirationDateYear, expirationDateHour, expirationDateMinute,
145             neverExpire, reviewDateMonth, reviewDateDay, reviewDateYear,
146             reviewDateHour, reviewDateMinute, neverReview, indexable,
147             smallImage, smallImageURL, smallFile, images, articleURL,
148             serviceContext);
149     }
150 
151     public JournalArticle addArticle(
152             long userId, long groupId, String articleId, boolean autoArticleId,
153             String title, String description, String content, String type,
154             String structureId, String templateId, int displayDateMonth,
155             int displayDateDay, int displayDateYear, int displayDateHour,
156             int displayDateMinute, int expirationDateMonth,
157             int expirationDateDay, int expirationDateYear,
158             int expirationDateHour, int expirationDateMinute,
159             boolean neverExpire, int reviewDateMonth, int reviewDateDay,
160             int reviewDateYear, int reviewDateHour, int reviewDateMinute,
161             boolean neverReview, boolean indexable, boolean smallImage,
162             String smallImageURL, File smallFile, Map<String, byte[]> images,
163             String articleURL, ServiceContext serviceContext)
164         throws PortalException, SystemException {
165 
166         double version = JournalArticleImpl.DEFAULT_VERSION;
167 
168         return addArticle(
169             userId, groupId, articleId, autoArticleId, version, title,
170             description, content, type, structureId, templateId,
171             displayDateMonth, displayDateDay, displayDateYear, displayDateHour,
172             displayDateMinute, expirationDateMonth, expirationDateDay,
173             expirationDateYear, expirationDateHour, expirationDateMinute,
174             neverExpire, reviewDateMonth, reviewDateDay, reviewDateYear,
175             reviewDateHour, reviewDateMinute, neverReview, indexable,
176             smallImage, smallImageURL, smallFile, images, articleURL,
177             serviceContext);
178     }
179 
180     public JournalArticle addArticle(
181             String uuid, long userId, long groupId, String articleId,
182             boolean autoArticleId, double version, String title,
183             String description, String content, String type, String structureId,
184             String templateId, int displayDateMonth, int displayDateDay,
185             int displayDateYear, int displayDateHour, int displayDateMinute,
186             int expirationDateMonth, int expirationDateDay,
187             int expirationDateYear, int expirationDateHour,
188             int expirationDateMinute, boolean neverExpire, int reviewDateMonth,
189             int reviewDateDay, int reviewDateYear, int reviewDateHour,
190             int reviewDateMinute, boolean neverReview, boolean indexable,
191             boolean smallImage, String smallImageURL, File smallFile,
192             Map<String, byte[]> images, String articleURL,
193             ServiceContext serviceContext)
194         throws PortalException, SystemException {
195 
196         // Article
197 
198         User user = userPersistence.findByPrimaryKey(userId);
199         articleId = articleId.trim().toUpperCase();
200 
201         Date displayDate = PortalUtil.getDate(
202             displayDateMonth, displayDateDay, displayDateYear,
203             displayDateHour, displayDateMinute, user.getTimeZone(),
204             new ArticleDisplayDateException());
205 
206         Date expirationDate = null;
207 
208         if (!neverExpire) {
209             expirationDate = PortalUtil.getDate(
210                 expirationDateMonth, expirationDateDay, expirationDateYear,
211                 expirationDateHour, expirationDateMinute, user.getTimeZone(),
212                 new ArticleExpirationDateException());
213         }
214 
215         Date reviewDate = null;
216 
217         if (!neverReview) {
218             reviewDate = PortalUtil.getDate(
219                 reviewDateMonth, reviewDateDay, reviewDateYear, reviewDateHour,
220                 reviewDateMinute, user.getTimeZone(),
221                 new ArticleReviewDateException());
222         }
223 
224         byte[] smallBytes = null;
225 
226         try {
227             smallBytes = FileUtil.getBytes(smallFile);
228         }
229         catch (IOException ioe) {
230         }
231 
232         Date now = new Date();
233 
234         validate(
235             groupId, articleId, autoArticleId, version, title, content, type,
236             structureId, templateId, smallImage, smallImageURL, smallFile,
237             smallBytes);
238 
239         if (autoArticleId) {
240             articleId = String.valueOf(counterLocalService.increment());
241         }
242 
243         long id = counterLocalService.increment();
244 
245         long resourcePrimKey =
246             journalArticleResourceLocalService.getArticleResourcePrimKey(
247                 groupId, articleId);
248 
249         JournalArticle article = journalArticlePersistence.create(id);
250 
251         content = format(
252             groupId, articleId, version, false, content, structureId, images);
253 
254         article.setUuid(uuid);
255         article.setResourcePrimKey(resourcePrimKey);
256         article.setGroupId(groupId);
257         article.setCompanyId(user.getCompanyId());
258         article.setUserId(user.getUserId());
259         article.setUserName(user.getFullName());
260         article.setCreateDate(serviceContext.getCreateDate(now));
261         article.setModifiedDate(serviceContext.getModifiedDate(now));
262         article.setArticleId(articleId);
263         article.setVersion(version);
264         article.setTitle(title);
265         article.setUrlTitle(getUniqueUrlTitle(id, groupId, articleId, title));
266         article.setDescription(description);
267         article.setContent(content);
268         article.setType(type);
269         article.setStructureId(structureId);
270         article.setTemplateId(templateId);
271         article.setDisplayDate(displayDate);
272         article.setApproved(false);
273 
274         if ((expirationDate == null) || expirationDate.after(now)) {
275             article.setExpired(false);
276         }
277         else {
278             article.setExpired(true);
279         }
280 
281         article.setExpirationDate(expirationDate);
282         article.setReviewDate(reviewDate);
283         article.setIndexable(indexable);
284         article.setSmallImage(smallImage);
285         article.setSmallImageId(counterLocalService.increment());
286         article.setSmallImageURL(smallImageURL);
287 
288         journalArticlePersistence.update(article, false);
289 
290         updateUrlTitles(groupId, articleId, article.getUrlTitle());
291 
292         // Resources
293 
294         if (serviceContext.getAddCommunityPermissions() ||
295             serviceContext.getAddGuestPermissions()) {
296 
297             addArticleResources(
298                 article, serviceContext.getAddCommunityPermissions(),
299                 serviceContext.getAddGuestPermissions());
300         }
301         else {
302             addArticleResources(
303                 article, serviceContext.getCommunityPermissions(),
304                 serviceContext.getGuestPermissions());
305         }
306 
307         // Expando
308 
309         ExpandoBridge expandoBridge = article.getExpandoBridge();
310 
311         expandoBridge.setAttributes(serviceContext);
312 
313         // Small image
314 
315         saveImages(
316             smallImage, article.getSmallImageId(), smallFile, smallBytes);
317 
318         // Message boards
319 
320         if (PropsValues.JOURNAL_ARTICLE_COMMENTS_ENABLED) {
321             mbMessageLocalService.addDiscussionMessage(
322                 userId, article.getUserName(),
323                 JournalArticle.class.getName(), resourcePrimKey);
324         }
325 
326         // Tags
327 
328         updateTagsAsset(
329             userId, article, serviceContext.getTagsCategories(),
330             serviceContext.getTagsEntries());
331 
332         // Email
333 
334         PortletPreferences preferences =
335             ServiceContextUtil.getPortletPreferences(serviceContext);
336 
337         try {
338             sendEmail(article, articleURL, preferences, "requested");
339         }
340         catch (IOException ioe) {
341             throw new SystemException(ioe);
342         }
343 
344         return article;
345     }
346 
347     public void addArticleResources(
348             JournalArticle article, boolean addCommunityPermissions,
349             boolean addGuestPermissions)
350         throws PortalException, SystemException {
351 
352         resourceLocalService.addResources(
353             article.getCompanyId(), article.getGroupId(),
354             article.getUserId(), JournalArticle.class.getName(),
355             article.getResourcePrimKey(), false, addCommunityPermissions,
356             addGuestPermissions);
357     }
358 
359     public void addArticleResources(
360             JournalArticle article, String[] communityPermissions,
361             String[] guestPermissions)
362         throws PortalException, SystemException {
363 
364         resourceLocalService.addModelResources(
365             article.getCompanyId(), article.getGroupId(),
366             article.getUserId(), JournalArticle.class.getName(),
367             article.getResourcePrimKey(), communityPermissions,
368             guestPermissions);
369     }
370 
371     public void addArticleResources(
372             long groupId, String articleId, boolean addCommunityPermissions,
373             boolean addGuestPermissions)
374         throws PortalException, SystemException {
375 
376         JournalArticle article = getLatestArticle(groupId, articleId);
377 
378         addArticleResources(
379             article, addCommunityPermissions, addGuestPermissions);
380     }
381 
382     public void addArticleResources(
383             long groupId, String articleId, String[] communityPermissions,
384             String[] guestPermissions)
385         throws PortalException, SystemException {
386 
387         JournalArticle article = getLatestArticle(groupId, articleId);
388 
389         addArticleResources(article, communityPermissions, guestPermissions);
390     }
391 
392     public JournalArticle approveArticle(
393             long userId, long groupId, String articleId, double version,
394             String articleURL, ServiceContext serviceContext)
395         throws PortalException, SystemException {
396 
397         // Article
398 
399         User user = userPersistence.findByPrimaryKey(userId);
400         Date now = new Date();
401 
402         JournalArticle article = journalArticlePersistence.findByG_A_V(
403             groupId, articleId, version);
404 
405         article.setModifiedDate(now);
406         article.setApproved(true);
407         article.setApprovedByUserId(user.getUserId());
408         article.setApprovedByUserName(user.getFullName());
409         article.setApprovedDate(now);
410         article.setExpired(false);
411 
412         if ((article.getExpirationDate() != null) &&
413             (article.getExpirationDate().before(now))) {
414 
415             article.setExpirationDate(null);
416         }
417 
418         journalArticlePersistence.update(article, false);
419 
420         // Expando
421 
422         ExpandoBridge expandoBridge = article.getExpandoBridge();
423 
424         expandoBridge.setAttributes(serviceContext);
425 
426         // Tags
427 
428         tagsAssetLocalService.updateVisible(
429             JournalArticle.class.getName(), article.getResourcePrimKey(), true);
430 
431         // Email
432 
433         PortletPreferences preferences =
434             ServiceContextUtil.getPortletPreferences(serviceContext);
435 
436         try {
437             sendEmail(article, articleURL, preferences, "granted");
438         }
439         catch (IOException ioe) {
440             throw new SystemException(ioe);
441         }
442 
443         // Indexer
444 
445         reIndex(article);
446 
447         return article;
448     }
449 
450     public JournalArticle checkArticleResourcePrimKey(
451             long groupId, String articleId, double version)
452         throws PortalException, SystemException {
453 
454         JournalArticle article = journalArticlePersistence.findByG_A_V(
455             groupId, articleId, version);
456 
457         if (article.getResourcePrimKey() > 0) {
458             return article;
459         }
460 
461         long resourcePrimKey =
462             journalArticleResourceLocalService.getArticleResourcePrimKey(
463                 groupId, articleId);
464 
465         article.setResourcePrimKey(resourcePrimKey);
466 
467         journalArticlePersistence.update(article, false);
468 
469         return article;
470     }
471 
472     public void checkArticles() throws PortalException, SystemException {
473         Date now = new Date();
474 
475         List<JournalArticle> articles =
476             journalArticleFinder.findByExpirationDate(
477                 Boolean.FALSE, now,
478                 new Date(now.getTime() - CheckArticleJob.INTERVAL));
479 
480         if (_log.isDebugEnabled()) {
481             _log.debug("Expiring " + articles.size() + " articles");
482         }
483 
484         Set<Long> companyIds = new HashSet<Long>();
485 
486         for (JournalArticle article : articles) {
487             article.setApproved(false);
488             article.setExpired(true);
489 
490             journalArticlePersistence.update(article, false);
491 
492             try {
493                 if (article.isIndexable()) {
494                     Indexer.deleteArticle(
495                         article.getCompanyId(), article.getGroupId(),
496                         article.getArticleId());
497                 }
498             }
499             catch (SearchException se) {
500                 _log.error("Removing index " + article.getId(), se);
501             }
502 
503             JournalContentUtil.clearCache(
504                 article.getGroupId(), article.getArticleId(),
505                 article.getTemplateId());
506 
507             companyIds.add(article.getCompanyId());
508         }
509 
510         for (long companyId : companyIds) {
511             CacheUtil.clearCache(companyId);
512         }
513 
514         articles = journalArticleFinder.findByReviewDate(
515             now, new Date(now.getTime() - CheckArticleJob.INTERVAL));
516 
517         if (_log.isDebugEnabled()) {
518             _log.debug(
519                 "Sending review notifications for " + articles.size() +
520                     " articles");
521         }
522 
523         for (JournalArticle article : articles) {
524             String articleURL = StringPool.BLANK;
525 
526             long ownerId = article.getGroupId();
527             int ownerType = PortletKeys.PREFS_OWNER_TYPE_GROUP;
528             long plid = PortletKeys.PREFS_PLID_SHARED;
529             String portletId = PortletKeys.JOURNAL;
530 
531             PortletPreferences preferences =
532                 portletPreferencesLocalService.getPreferences(
533                     article.getCompanyId(), ownerId, ownerType, plid,
534                     portletId);
535 
536             try {
537                 sendEmail(article, articleURL, preferences, "review");
538             }
539             catch (IOException ioe) {
540                 throw new SystemException(ioe);
541             }
542         }
543     }
544 
545     public void checkNewLine(long groupId, String articleId, double version)
546         throws PortalException, SystemException {
547 
548         JournalArticle article = journalArticlePersistence.findByG_A_V(
549             groupId, articleId, version);
550 
551         String content = GetterUtil.getString(article.getContent());
552 
553         if (content.indexOf("\\n") != -1) {
554             content = StringUtil.replace(
555                 content,
556                 new String[] {"\\n", "\\r"},
557                 new String[] {"\n", "\r"});
558 
559             article.setContent(content);
560 
561             journalArticlePersistence.update(article, false);
562         }
563     }
564 
565     public void checkStructure(long groupId, String articleId, double version)
566         throws PortalException, SystemException {
567 
568         JournalArticle article = journalArticlePersistence.findByG_A_V(
569             groupId, articleId, version);
570 
571         if (Validator.isNull(article.getStructureId())) {
572             return;
573         }
574 
575         try {
576             checkStructure(article);
577         }
578         catch (DocumentException de) {
579             _log.error(de, de);
580         }
581     }
582 
583     public JournalArticle copyArticle(
584             long userId, long groupId, String oldArticleId, String newArticleId,
585             boolean autoArticleId, double version)
586         throws PortalException, SystemException {
587 
588         // Article
589 
590         User user = userPersistence.findByPrimaryKey(userId);
591         oldArticleId = oldArticleId.trim().toUpperCase();
592         newArticleId = newArticleId.trim().toUpperCase();
593         Date now = new Date();
594 
595         JournalArticle oldArticle = journalArticlePersistence.findByG_A_V(
596             groupId, oldArticleId, version);
597 
598         if (autoArticleId) {
599             newArticleId = String.valueOf(counterLocalService.increment());
600         }
601         else {
602             validate(newArticleId);
603 
604             JournalArticle newArticle = journalArticlePersistence.fetchByG_A_V(
605                 groupId, newArticleId, version);
606 
607             if (newArticle != null) {
608                 throw new DuplicateArticleIdException();
609             }
610         }
611 
612         long id = counterLocalService.increment();
613 
614         long resourcePrimKey =
615             journalArticleResourceLocalService.getArticleResourcePrimKey(
616                 groupId, newArticleId);
617 
618         JournalArticle newArticle = journalArticlePersistence.create(id);
619 
620         newArticle.setResourcePrimKey(resourcePrimKey);
621         newArticle.setGroupId(groupId);
622         newArticle.setCompanyId(user.getCompanyId());
623         newArticle.setUserId(user.getUserId());
624         newArticle.setUserName(user.getFullName());
625         newArticle.setCreateDate(now);
626         newArticle.setModifiedDate(now);
627         newArticle.setArticleId(newArticleId);
628         newArticle.setVersion(JournalArticleImpl.DEFAULT_VERSION);
629         newArticle.setTitle(oldArticle.getTitle());
630         newArticle.setDescription(oldArticle.getDescription());
631 
632         try {
633             copyArticleImages(oldArticle, newArticle);
634         }
635         catch (Exception e) {
636             newArticle.setContent(oldArticle.getContent());
637         }
638 
639         newArticle.setType(oldArticle.getType());
640         newArticle.setStructureId(oldArticle.getStructureId());
641         newArticle.setTemplateId(oldArticle.getTemplateId());
642         newArticle.setDisplayDate(oldArticle.getDisplayDate());
643         newArticle.setApproved(oldArticle.isApproved());
644         newArticle.setExpired(oldArticle.isExpired());
645         newArticle.setExpirationDate(oldArticle.getExpirationDate());
646         newArticle.setReviewDate(oldArticle.getReviewDate());
647         newArticle.setIndexable(oldArticle.isIndexable());
648         newArticle.setSmallImage(oldArticle.isSmallImage());
649         newArticle.setSmallImageId(counterLocalService.increment());
650         newArticle.setSmallImageURL(oldArticle.getSmallImageURL());
651 
652         journalArticlePersistence.update(newArticle, false);
653 
654         // Resources
655 
656         addArticleResources(newArticle, true, true);
657 
658         // Small image
659 
660         if (oldArticle.getSmallImage()) {
661             Image image = imageLocalService.getImage(
662                 oldArticle.getSmallImageId());
663 
664             byte[] smallBytes = image.getTextObj();
665 
666             imageLocalService.updateImage(
667                 newArticle.getSmallImageId(), smallBytes);
668         }
669 
670         // Tags
671 
672         String[] tagsCategories = tagsEntryLocalService.getEntryNames(
673             JournalArticle.class.getName(), oldArticle.getResourcePrimKey(),
674             TagsEntryConstants.FOLKSONOMY_CATEGORY);
675         String[] tagsEntries = tagsEntryLocalService.getEntryNames(
676             JournalArticle.class.getName(), oldArticle.getResourcePrimKey(),
677             TagsEntryConstants.FOLKSONOMY_TAG);
678 
679         updateTagsAsset(userId, newArticle, tagsCategories, tagsEntries);
680 
681         return newArticle;
682     }
683 
684     public void deleteArticle(
685             JournalArticle article, String articleURL,
686             ServiceContext serviceContext)
687         throws PortalException, SystemException {
688 
689         // Indexer
690 
691         try {
692             if (article.isApproved() && article.isIndexable()) {
693                 Indexer.deleteArticle(
694                     article.getCompanyId(), article.getGroupId(),
695                     article.getArticleId());
696             }
697         }
698         catch (SearchException se) {
699             _log.error("Deleting index " + article.getPrimaryKey(), se);
700         }
701 
702         // Email
703 
704         PortletPreferences preferences =
705             ServiceContextUtil.getPortletPreferences(serviceContext);
706 
707         if ((preferences != null) && !article.isApproved() &&
708             isLatestVersion(
709                 article.getGroupId(), article.getArticleId(),
710                 article.getVersion())) {
711 
712             try {
713                 sendEmail(article, articleURL, preferences, "denied");
714             }
715             catch (IOException ioe) {
716                 throw new SystemException(ioe);
717             }
718         }
719 
720         // Images
721 
722         journalArticleImageLocalService.deleteImages(
723             article.getGroupId(), article.getArticleId(), article.getVersion());
724 
725         int articlesCount = journalArticlePersistence.countByG_A(
726             article.getGroupId(), article.getArticleId());
727 
728         if (articlesCount == 1) {
729 
730             // Tags
731 
732             tagsAssetLocalService.deleteAsset(
733                 JournalArticle.class.getName(), article.getResourcePrimKey());
734 
735             // Ratings
736 
737             ratingsStatsLocalService.deleteStats(
738                 JournalArticle.class.getName(), article.getResourcePrimKey());
739 
740             // Message boards
741 
742             mbMessageLocalService.deleteDiscussionMessages(
743                 JournalArticle.class.getName(), article.getResourcePrimKey());
744 
745             // Content searches
746 
747             journalContentSearchLocalService.deleteArticleContentSearches(
748                 article.getGroupId(), article.getArticleId());
749 
750             // Small image
751 
752             imageLocalService.deleteImage(article.getSmallImageId());
753 
754             // Expando
755 
756             expandoValueLocalService.deleteValues(
757                 JournalArticle.class.getName(), article.getResourcePrimKey());
758 
759             // Resources
760 
761             resourceLocalService.deleteResource(
762                 article.getCompanyId(), JournalArticle.class.getName(),
763                 ResourceConstants.SCOPE_INDIVIDUAL,
764                 article.getResourcePrimKey());
765 
766             // Resource
767 
768             try {
769                 journalArticleResourceLocalService.deleteArticleResource(
770                     article.getGroupId(), article.getArticleId());
771             }
772             catch (NoSuchArticleResourceException nsare) {
773             }
774         }
775 
776         // Article
777 
778         journalArticlePersistence.remove(article);
779     }
780 
781     public void deleteArticle(
782             long groupId, String articleId, double version, String articleURL,
783             ServiceContext serviceContext)
784         throws PortalException, SystemException {
785 
786         JournalArticle article = journalArticlePersistence.findByG_A_V(
787             groupId, articleId, version);
788 
789         deleteArticle(article, articleURL, serviceContext);
790     }
791 
792     public void deleteArticles(long groupId)
793         throws PortalException, SystemException {
794 
795         for (JournalArticle article :
796                 journalArticlePersistence.findByGroupId(groupId)) {
797 
798             deleteArticle(article, null, null);
799         }
800     }
801 
802     public void expireArticle(
803             JournalArticle article, String articleURL,
804             ServiceContext serviceContext)
805         throws PortalException, SystemException {
806 
807         // Email
808 
809         PortletPreferences preferences =
810             ServiceContextUtil.getPortletPreferences(serviceContext);
811 
812         if ((preferences != null) && !article.isApproved() &&
813             isLatestVersion(
814                 article.getGroupId(), article.getArticleId(),
815                 article.getVersion())) {
816 
817             try {
818                 sendEmail(article, articleURL, preferences, "denied");
819             }
820             catch (IOException ioe) {
821                 throw new SystemException(ioe);
822             }
823         }
824 
825         // Article
826 
827         article.setExpirationDate(new Date());
828 
829         article.setApproved(false);
830         article.setExpired(true);
831 
832         journalArticlePersistence.update(article, false);
833 
834         // Tags
835 
836         tagsAssetLocalService.updateVisible(
837             JournalArticle.class.getName(), article.getResourcePrimKey(),
838             false);
839 
840         // Indexer
841 
842         try {
843             if (article.isIndexable()) {
844                 Indexer.deleteArticle(
845                     article.getCompanyId(), article.getGroupId(),
846                     article.getArticleId());
847             }
848         }
849         catch (SearchException se) {
850             _log.error("Removing index " + article.getId(), se);
851         }
852     }
853 
854     public void expireArticle(
855             long groupId, String articleId, double version, String articleURL,
856             ServiceContext serviceContext)
857         throws PortalException, SystemException {
858 
859         JournalArticle article = journalArticlePersistence.findByG_A_V(
860             groupId, articleId, version);
861 
862         expireArticle(article, articleURL, serviceContext);
863     }
864 
865     public JournalArticle getArticle(long id)
866         throws PortalException, SystemException {
867 
868         return journalArticlePersistence.findByPrimaryKey(id);
869     }
870 
871     public JournalArticle getArticle(long groupId, String articleId)
872         throws PortalException, SystemException {
873 
874         // Get the latest article that is approved, if none are approved, get
875         // the latest unapproved article
876 
877         try {
878             return getLatestArticle(groupId, articleId, Boolean.TRUE);
879         }
880         catch (NoSuchArticleException nsae) {
881             return getLatestArticle(groupId, articleId, Boolean.FALSE);
882         }
883     }
884 
885     public JournalArticle getArticle(
886             long groupId, String articleId, double version)
887         throws PortalException, SystemException {
888 
889         return journalArticlePersistence.findByG_A_V(
890             groupId, articleId, version);
891     }
892 
893     public JournalArticle getArticleByUrlTitle(long groupId, String urlTitle)
894         throws PortalException, SystemException {
895 
896         // Get the latest article that is approved, if none are approved, get
897         // the latest unapproved article
898 
899         try {
900             return getLatestArticleByUrlTitle(groupId, urlTitle, Boolean.TRUE);
901         }
902         catch (NoSuchArticleException nsae) {
903             return getLatestArticleByUrlTitle(groupId, urlTitle, Boolean.FALSE);
904         }
905     }
906 
907     public String getArticleContent(
908             JournalArticle article, String templateId, String viewMode,
909             String languageId, ThemeDisplay themeDisplay)
910         throws SystemException {
911 
912         JournalArticleDisplay articleDisplay = getArticleDisplay(
913             article, templateId, viewMode, languageId, 1, null, themeDisplay);
914 
915         if (articleDisplay == null) {
916             return StringPool.BLANK;
917         }
918         else {
919             return articleDisplay.getContent();
920         }
921     }
922 
923     public String getArticleContent(
924             long groupId, String articleId, double version, String viewMode,
925             String templateId, String languageId, ThemeDisplay themeDisplay)
926         throws PortalException, SystemException {
927 
928         JournalArticleDisplay articleDisplay = getArticleDisplay(
929             groupId, articleId, version, templateId, viewMode, languageId,
930             themeDisplay);
931 
932         if (articleDisplay == null) {
933             return StringPool.BLANK;
934         }
935         else {
936             return articleDisplay.getContent();
937         }
938     }
939 
940     public String getArticleContent(
941             long groupId, String articleId, double version, String viewMode,
942             String languageId, ThemeDisplay themeDisplay)
943         throws PortalException, SystemException {
944 
945         return getArticleContent(
946             groupId, articleId, version, viewMode, null, languageId,
947             themeDisplay);
948     }
949 
950     public String getArticleContent(
951             long groupId, String articleId, String viewMode, String templateId,
952             String languageId, ThemeDisplay themeDisplay)
953         throws PortalException, SystemException {
954 
955         JournalArticleDisplay articleDisplay = getArticleDisplay(
956             groupId, articleId, templateId, viewMode, languageId, themeDisplay);
957 
958         return articleDisplay.getContent();
959     }
960 
961     public String getArticleContent(
962             long groupId, String articleId, String viewMode, String languageId,
963             ThemeDisplay themeDisplay)
964         throws PortalException, SystemException {
965 
966         return getArticleContent(
967             groupId, articleId, viewMode, null, languageId, themeDisplay);
968     }
969 
970     public JournalArticleDisplay getArticleDisplay(
971             JournalArticle article, String templateId, String viewMode,
972             String languageId, int page, String xmlRequest,
973             ThemeDisplay themeDisplay)
974         throws SystemException {
975 
976         String content = null;
977 
978         if (page < 1) {
979             page = 1;
980         }
981 
982         int numberOfPages = 1;
983         boolean paginate = false;
984         boolean pageFlow = false;
985 
986         boolean cacheable = true;
987 
988         if (Validator.isNull(xmlRequest)) {
989             xmlRequest = "<request />";
990         }
991 
992         Map<String, String> tokens = JournalUtil.getTokens(
993             article.getGroupId(), themeDisplay, xmlRequest);
994 
995         tokens.put(
996             "article_resource_pk",
997             String.valueOf(article.getResourcePrimKey()));
998 
999         String defaultTemplateId = article.getTemplateId();
1000
1001        if (article.isTemplateDriven()) {
1002            if (Validator.isNull(templateId)) {
1003                templateId = defaultTemplateId;
1004            }
1005
1006            tokens.put("structure_id", article.getStructureId());
1007            tokens.put("template_id", templateId);
1008        }
1009
1010        String xml = article.getContent();
1011
1012        try {
1013            Document doc = null;
1014
1015            Element root = null;
1016
1017            if (article.isTemplateDriven()) {
1018                doc = SAXReaderUtil.read(xml);
1019
1020                root = doc.getRootElement();
1021
1022                Document request = SAXReaderUtil.read(xmlRequest);
1023
1024                List<Element> pages = root.elements("page");
1025
1026                if (pages.size() > 0) {
1027                    pageFlow = true;
1028
1029                    String targetPage = request.valueOf(
1030                        "/request/parameters/parameter[name='targetPage']/" +
1031                            "value");
1032
1033                    Element pageEl = null;
1034
1035                    if (Validator.isNotNull(targetPage)) {
1036                        XPath xpathSelector = SAXReaderUtil.createXPath(
1037                            "/root/page[@id = '" + targetPage + "']");
1038
1039                        pageEl = (Element)xpathSelector.selectSingleNode(doc);
1040                    }
1041
1042                    if (pageEl != null) {
1043                        doc = SAXReaderUtil.createDocument(pageEl);
1044
1045                        root = doc.getRootElement();
1046
1047                        numberOfPages = pages.size();
1048                    }
1049                    else {
1050                        if (page > pages.size()) {
1051                            page = 1;
1052                        }
1053
1054                        pageEl = pages.get(page - 1);
1055
1056                        doc = SAXReaderUtil.createDocument(pageEl);
1057
1058                        root = doc.getRootElement();
1059
1060                        numberOfPages = pages.size();
1061                        paginate = true;
1062                    }
1063                }
1064
1065                root.add(request.getRootElement().createCopy());
1066
1067                JournalUtil.addAllReservedEls(root, tokens, article);
1068
1069                xml = JournalUtil.formatXML(doc);
1070            }
1071        }
1072        catch (DocumentException de) {
1073            throw new SystemException(de);
1074        }
1075        catch (IOException ioe) {
1076            throw new SystemException(ioe);
1077        }
1078
1079        try {
1080            if (_log.isDebugEnabled()) {
1081                _log.debug(
1082                    "Transforming " + article.getArticleId() + " " +
1083                        article.getVersion() + " " + languageId);
1084            }
1085
1086            String script = null;
1087            String langType = null;
1088
1089            if (article.isTemplateDriven()) {
1090
1091                // Try with specified template first. If a template is not
1092                // specified, use the default one. If the specified template
1093                // does not exit, use the default one. If the default one does
1094                // not exist, throw an exception.
1095
1096                JournalTemplate template = null;
1097
1098                try {
1099                    template = journalTemplatePersistence.findByG_T(
1100                        article.getGroupId(), templateId);
1101                }
1102                catch (NoSuchTemplateException nste) {
1103                    if (!defaultTemplateId.equals(templateId)) {
1104                        template = journalTemplatePersistence.findByG_T(
1105                            article.getGroupId(), defaultTemplateId);
1106                    }
1107                    else {
1108                        throw nste;
1109                    }
1110                }
1111
1112                script = template.getXsl();
1113                langType = template.getLangType();
1114                cacheable = template.isCacheable();
1115            }
1116
1117            content = JournalUtil.transform(
1118                themeDisplay, tokens, viewMode, languageId, xml, script,
1119                langType);
1120
1121            if (!pageFlow) {
1122                String[] pieces = StringUtil.split(content, _TOKEN_PAGE_BREAK);
1123
1124                if (pieces.length > 1) {
1125                    if (page > pieces.length) {
1126                        page = 1;
1127                    }
1128
1129                    content = pieces[page - 1];
1130                    numberOfPages = pieces.length;
1131                    paginate = true;
1132                }
1133            }
1134        }
1135        catch (Exception e) {
1136            throw new SystemException(e);
1137        }
1138
1139        return new JournalArticleDisplayImpl(
1140            article.getId(), article.getResourcePrimKey(), article.getGroupId(),
1141            article.getUserId(), article.getArticleId(), article.getVersion(),
1142            article.getTitle(), article.getUrlTitle(), article.getDescription(),
1143            article.getAvailableLocales(), content, article.getType(),
1144            article.getStructureId(), templateId, article.isSmallImage(),
1145            article.getSmallImageId(), article.getSmallImageURL(),
1146            numberOfPages, page, paginate, cacheable);
1147    }
1148
1149    public JournalArticleDisplay getArticleDisplay(
1150            long groupId, String articleId, double version, String templateId,
1151            String viewMode, String languageId, int page, String xmlRequest,
1152            ThemeDisplay themeDisplay)
1153        throws PortalException, SystemException {
1154
1155        Date now = new Date();
1156
1157        JournalArticle article = journalArticlePersistence.findByG_A_V(
1158            groupId, articleId, version);
1159
1160        if (article.isExpired()) {
1161            Date expirationDate = article.getExpirationDate();
1162
1163            if ((expirationDate != null) && expirationDate.before(now)) {
1164                return null;
1165            }
1166        }
1167
1168        if (article.getDisplayDate().after(now)) {
1169            return null;
1170        }
1171
1172        return getArticleDisplay(
1173            article, templateId, viewMode, languageId, page, xmlRequest,
1174            themeDisplay);
1175    }
1176
1177    public JournalArticleDisplay getArticleDisplay(
1178            long groupId, String articleId, double version, String templateId,
1179            String viewMode, String languageId, ThemeDisplay themeDisplay)
1180        throws PortalException, SystemException {
1181
1182        return getArticleDisplay(
1183            groupId, articleId, version, templateId, viewMode, languageId, 1,
1184            null, themeDisplay);
1185    }
1186
1187    public JournalArticleDisplay getArticleDisplay(
1188            long groupId, String articleId, String viewMode, String languageId,
1189            int page, String xmlRequest, ThemeDisplay themeDisplay)
1190        throws PortalException, SystemException {
1191
1192        return getArticleDisplay(
1193            groupId, articleId, null, viewMode, languageId, page, xmlRequest,
1194            themeDisplay);
1195    }
1196
1197    public JournalArticleDisplay getArticleDisplay(
1198            long groupId, String articleId, String templateId, String viewMode,
1199            String languageId, int page, String xmlRequest,
1200            ThemeDisplay themeDisplay)
1201        throws PortalException, SystemException {
1202
1203        JournalArticle article = getDisplayArticle(groupId, articleId);
1204
1205        return getArticleDisplay(
1206            groupId, articleId, article.getVersion(), templateId, viewMode,
1207            languageId, page, xmlRequest, themeDisplay);
1208    }
1209
1210    public JournalArticleDisplay getArticleDisplay(
1211            long groupId, String articleId, String templateId, String viewMode,
1212            String languageId, ThemeDisplay themeDisplay)
1213        throws PortalException, SystemException {
1214
1215        JournalArticle article = getDisplayArticle(groupId, articleId);
1216
1217        return getArticleDisplay(
1218            groupId, articleId, article.getVersion(), templateId, viewMode,
1219            languageId, themeDisplay);
1220    }
1221
1222    public JournalArticleDisplay getArticleDisplay(
1223            long groupId, String articleId, String viewMode, String languageId,
1224            ThemeDisplay themeDisplay)
1225        throws PortalException, SystemException {
1226
1227        return getArticleDisplay(
1228            groupId, articleId, null, viewMode, languageId, themeDisplay);
1229    }
1230
1231    public List<JournalArticle> getArticles() throws SystemException {
1232        return journalArticlePersistence.findAll();
1233    }
1234
1235    public List<JournalArticle> getArticles(long groupId)
1236        throws SystemException {
1237
1238        return journalArticlePersistence.findByGroupId(groupId);
1239    }
1240
1241    public List<JournalArticle> getArticles(long groupId, int start, int end)
1242        throws SystemException {
1243
1244        return journalArticlePersistence.findByGroupId(groupId, start, end);
1245    }
1246
1247    public List<JournalArticle> getArticles(
1248            long groupId, int start, int end, OrderByComparator obc)
1249        throws SystemException {
1250
1251        return journalArticlePersistence.findByGroupId(
1252            groupId, start, end, obc);
1253    }
1254
1255    public List<JournalArticle> getArticles(long groupId, String articleId)
1256        throws SystemException {
1257
1258        return journalArticlePersistence.findByG_A(groupId, articleId);
1259    }
1260
1261    public List<JournalArticle> getArticlesBySmallImageId(long smallImageId)
1262        throws SystemException {
1263
1264        return journalArticlePersistence.findBySmallImageId(smallImageId);
1265    }
1266
1267    public int getArticlesCount(long groupId) throws SystemException {
1268        return journalArticlePersistence.countByGroupId(groupId);
1269    }
1270
1271    public JournalArticle getDisplayArticle(long groupId, String articleId)
1272        throws PortalException, SystemException {
1273
1274        List<JournalArticle> articles = journalArticlePersistence.findByG_A_A(
1275            groupId, articleId, true);
1276
1277        if (articles.size() == 0) {
1278            throw new NoSuchArticleException();
1279        }
1280
1281        Date now = new Date();
1282
1283        for (int i = 0; i < articles.size(); i++) {
1284            JournalArticle article = articles.get(i);
1285
1286            Date expirationDate = article.getExpirationDate();
1287
1288            if (article.getDisplayDate().before(now) &&
1289                ((expirationDate == null) || expirationDate.after(now))) {
1290
1291                return article;
1292            }
1293        }
1294
1295        return articles.get(0);
1296    }
1297
1298    public JournalArticle getLatestArticle(long resourcePrimKey)
1299        throws PortalException, SystemException {
1300
1301        return getLatestArticle(resourcePrimKey, (Boolean)null);
1302    }
1303
1304    public JournalArticle getLatestArticle(
1305            long resourcePrimKey, Boolean approved)
1306        throws PortalException, SystemException {
1307
1308        List<JournalArticle> articles = null;
1309
1310        OrderByComparator orderByComparator = new ArticleVersionComparator();
1311
1312        if (approved == null) {
1313            articles = journalArticlePersistence.findByR_A(
1314                resourcePrimKey, true, 0, 1, orderByComparator);
1315
1316            if (articles.size() == 0) {
1317                articles = journalArticlePersistence.findByR_A(
1318                    resourcePrimKey, false, 0, 1, orderByComparator);
1319            }
1320        }
1321        else {
1322            articles = journalArticlePersistence.findByR_A(
1323                resourcePrimKey, approved.booleanValue(), 0, 1,
1324                orderByComparator);
1325        }
1326
1327        if (articles.size() == 0) {
1328            throw new NoSuchArticleException();
1329        }
1330
1331        return articles.get(0);
1332    }
1333
1334    public JournalArticle getLatestArticle(long groupId, String articleId)
1335        throws PortalException, SystemException {
1336
1337        return getLatestArticle(groupId, articleId, null);
1338    }
1339
1340    public JournalArticle getLatestArticle(
1341            long groupId, String articleId, Boolean approved)
1342        throws PortalException, SystemException {
1343
1344        List<JournalArticle> articles = null;
1345
1346        OrderByComparator orderByComparator = new ArticleVersionComparator();
1347
1348        if (approved == null) {
1349            articles = journalArticlePersistence.findByG_A(
1350                groupId, articleId, 0, 1, orderByComparator);
1351        }
1352        else {
1353            articles = journalArticlePersistence.findByG_A_A(
1354                groupId, articleId, approved.booleanValue(), 0, 1,
1355                orderByComparator);
1356        }
1357
1358        if (articles.size() == 0) {
1359            throw new NoSuchArticleException();
1360        }
1361
1362        return articles.get(0);
1363    }
1364
1365    public JournalArticle getLatestArticleByUrlTitle(
1366            long groupId, String urlTitle, Boolean approved)
1367        throws PortalException, SystemException {
1368
1369        List<JournalArticle> articles = null;
1370
1371        OrderByComparator orderByComparator = new ArticleVersionComparator();
1372
1373        if (approved == null) {
1374            articles = journalArticlePersistence.findByG_UT(
1375                groupId, urlTitle, 0, 1, orderByComparator);
1376        }
1377        else {
1378            articles = journalArticlePersistence.findByG_UT_A(
1379                groupId, urlTitle, approved.booleanValue(), 0, 1,
1380                orderByComparator);
1381        }
1382
1383        if (articles.size() == 0) {
1384            throw new NoSuchArticleException();
1385        }
1386
1387        return articles.get(0);
1388    }
1389
1390    public double getLatestVersion(long groupId, String articleId)
1391        throws PortalException, SystemException {
1392
1393        JournalArticle article = getLatestArticle(groupId, articleId);
1394
1395        return article.getVersion();
1396    }
1397
1398    public double getLatestVersion(
1399            long groupId, String articleId, Boolean approved)
1400        throws PortalException, SystemException {
1401
1402        JournalArticle article = getLatestArticle(groupId, articleId, approved);
1403
1404        return article.getVersion();
1405    }
1406
1407    public List<JournalArticle> getStructureArticles(
1408            long groupId, String structureId)
1409        throws SystemException {
1410
1411        return journalArticlePersistence.findByG_S(groupId, structureId);
1412    }
1413
1414    public List<JournalArticle> getStructureArticles(
1415            long groupId, String structureId, int start, int end,
1416            OrderByComparator obc)
1417        throws SystemException {
1418
1419        return journalArticlePersistence.findByG_S(
1420            groupId, structureId, start, end, obc);
1421    }
1422
1423    public int getStructureArticlesCount(long groupId, String structureId)
1424        throws SystemException {
1425
1426        return journalArticlePersistence.countByG_S(groupId, structureId);
1427    }
1428
1429    public List<JournalArticle> getTemplateArticles(
1430            long groupId, String templateId)
1431        throws SystemException {
1432
1433        return journalArticlePersistence.findByG_T(groupId, templateId);
1434    }
1435
1436    public List<JournalArticle> getTemplateArticles(
1437            long groupId, String templateId, int start, int end,
1438            OrderByComparator obc)
1439        throws SystemException {
1440
1441        return journalArticlePersistence.findByG_T(
1442            groupId, templateId, start, end, obc);
1443    }
1444
1445    public int getTemplateArticlesCount(long groupId, String templateId)
1446        throws SystemException {
1447
1448        return journalArticlePersistence.countByG_T(groupId, templateId);
1449    }
1450
1451    public boolean hasArticle(long groupId, String articleId)
1452        throws SystemException {
1453
1454        try {
1455            getArticle(groupId, articleId);
1456
1457            return true;
1458        }
1459        catch (PortalException pe) {
1460            return false;
1461        }
1462    }
1463
1464    public boolean isLatestVersion(
1465            long groupId, String articleId, double version)
1466        throws PortalException, SystemException {
1467
1468        if (getLatestVersion(groupId, articleId) == version) {
1469            return true;
1470        }
1471        else {
1472            return false;
1473        }
1474    }
1475
1476    public boolean isLatestVersion(
1477            long groupId, String articleId, double version, Boolean active)
1478        throws PortalException, SystemException {
1479
1480        if (getLatestVersion(groupId, articleId, active) == version) {
1481            return true;
1482        }
1483        else {
1484            return false;
1485        }
1486    }
1487
1488    public void reIndex(JournalArticle article) throws SystemException {
1489        if (!article.isApproved() || !article.isIndexable()) {
1490            return;
1491        }
1492
1493        long companyId = article.getCompanyId();
1494        long groupId = article.getGroupId();
1495        long userId = article.getUserId();
1496        long resourcePrimKey = article.getResourcePrimKey();
1497        String articleId = article.getArticleId();
1498        double version = article.getVersion();
1499        String title = article.getTitle();
1500        String description = article.getDescription();
1501        String content = article.getContent();
1502        String type = article.getType();
1503        Date displayDate = article.getDisplayDate();
1504
1505        String[] tagsCategories = tagsEntryLocalService.getEntryNames(
1506            JournalArticle.class.getName(), resourcePrimKey,
1507            TagsEntryConstants.FOLKSONOMY_CATEGORY);
1508        String[] tagsEntries = tagsEntryLocalService.getEntryNames(
1509            JournalArticle.class.getName(), resourcePrimKey);
1510
1511        ExpandoBridge expandoBridge = article.getExpandoBridge();
1512
1513        try {
1514            Indexer.updateArticle(
1515                companyId, groupId, userId, resourcePrimKey, articleId, version,
1516                title, description, content, type, displayDate, tagsCategories,
1517                tagsEntries, expandoBridge);
1518        }
1519        catch (SearchException se) {
1520            _log.error("Reindexing " + article.getId(), se);
1521        }
1522    }
1523
1524    public void reIndex(long resourcePrimKey) throws SystemException {
1525        if (SearchEngineUtil.isIndexReadOnly()) {
1526            return;
1527        }
1528
1529        JournalArticle article = null;
1530
1531        try {
1532            article = getLatestArticle(resourcePrimKey, Boolean.TRUE);
1533        }
1534        catch (Exception e) {
1535            if (e instanceof NoSuchArticleException) {
1536                return;
1537            }
1538        }
1539
1540        reIndex(article);
1541    }
1542
1543    public void reIndex(String[] ids) throws SystemException {
1544        if (SearchEngineUtil.isIndexReadOnly()) {
1545            return;
1546        }
1547
1548        long companyId = GetterUtil.getLong(ids[0]);
1549
1550        try {
1551            reIndexArticles(companyId);
1552        }
1553        catch (SystemException se) {
1554            throw se;
1555        }
1556        catch (Exception e) {
1557            throw new SystemException(e);
1558        }
1559    }
1560
1561    public JournalArticle removeArticleLocale(
1562            long groupId, String articleId, double version, String languageId)
1563        throws PortalException, SystemException {
1564
1565        JournalArticle article = journalArticlePersistence.findByG_A_V(
1566            groupId, articleId, version);
1567
1568        String content = article.getContent();
1569
1570        if (article.isTemplateDriven()) {
1571            content = JournalUtil.removeArticleLocale(content, languageId);
1572        }
1573        else {
1574            content = LocalizationUtil.removeLocalization(
1575                content, "static-content", languageId, true);
1576        }
1577
1578        article.setContent(content);
1579
1580        journalArticlePersistence.update(article, false);
1581
1582        return article;
1583    }
1584
1585    public Hits search(
1586            long companyId, long groupId, long userId, String keywords,
1587            int start, int end)
1588        throws SystemException {
1589
1590        return search(
1591            companyId, groupId, userId, keywords, null, start, end);
1592    }
1593
1594    public Hits search(
1595            long companyId, long groupId, long userId, String keywords,
1596            String type, int start, int end)
1597        throws SystemException {
1598
1599        Sort sort = new Sort("displayDate", Sort.LONG_TYPE, true);
1600
1601        return search(
1602            companyId, groupId, userId, keywords, type, new Sort[] {sort},
1603            start, end);
1604    }
1605
1606    public Hits search(
1607            long companyId, long groupId, long userId, String keywords,
1608            String type, List<BooleanClause> booleanClauses, Sort[] sorts,
1609            int start, int end)
1610        throws SystemException {
1611
1612        try {
1613            BooleanQuery contextQuery = BooleanQueryFactoryUtil.create();
1614
1615            contextQuery.addRequiredTerm(Field.PORTLET_ID, Indexer.PORTLET_ID);
1616
1617            if (groupId > 0) {
1618                contextQuery.addRequiredTerm(Field.GROUP_ID, groupId);
1619            }
1620
1621            BooleanQuery searchQuery = BooleanQueryFactoryUtil.create();
1622
1623            if (Validator.isNotNull(type)) {
1624                contextQuery.addRequiredTerm(Field.TYPE, type);
1625            }
1626            else {
1627                searchQuery.addTerm(Field.TYPE, keywords);
1628            }
1629
1630            if (Validator.isNotNull(keywords)) {
1631                searchQuery.addTerm(Field.TITLE, keywords);
1632                searchQuery.addTerm(Field.CONTENT, keywords);
1633                searchQuery.addTerm(Field.DESCRIPTION, keywords);
1634                searchQuery.addTerm(Field.TAGS_CATEGORIES, keywords);
1635                searchQuery.addTerm(Field.TAGS_ENTRIES, keywords, true);
1636            }
1637
1638            BooleanQuery fullQuery = BooleanQueryFactoryUtil.create();
1639
1640            fullQuery.add(contextQuery, BooleanClauseOccur.MUST);
1641
1642            if (searchQuery.clauses().size() > 0) {
1643                fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
1644            }
1645
1646            if (booleanClauses != null) {
1647                for (BooleanClause booleanClause : booleanClauses) {
1648                    fullQuery.add(
1649                        booleanClause.getQuery(),
1650                        booleanClause.getBooleanClauseOccur());
1651                }
1652            }
1653
1654            return SearchEngineUtil.search(
1655                companyId, groupId, userId, JournalArticle.class.getName(),
1656                fullQuery, sorts, start, end);
1657        }
1658        catch (Exception e) {
1659            throw new SystemException(e);
1660        }
1661    }
1662
1663    public Hits search(
1664            long companyId, long groupId, long userId, String keywords,
1665            String type, Sort sort, int start, int end)
1666        throws SystemException {
1667
1668        return search(
1669            companyId, groupId, userId, keywords, type, new Sort[] {sort},
1670            start, end);
1671    }
1672
1673    public Hits search(
1674            long companyId, long groupId, long userId, String keywords,
1675            String type, Sort[] sorts, int start, int end)
1676        throws SystemException {
1677
1678        List<BooleanClause> booleanClauses = null;
1679
1680        return search(
1681            companyId, groupId, userId, keywords, type, booleanClauses, sorts,
1682            start, end);
1683    }
1684
1685    public List<JournalArticle> search(
1686            long companyId, long groupId, String keywords, Double version,
1687            String type, String structureId, String templateId,
1688            Date displayDateGT, Date displayDateLT, Boolean approved,
1689            Boolean expired, Date reviewDate, int start, int end,
1690            OrderByComparator obc)
1691        throws SystemException {
1692
1693        return journalArticleFinder.findByKeywords(
1694            companyId, groupId, keywords, version, type, structureId,
1695            templateId, displayDateGT, displayDateLT, approved, expired,
1696            reviewDate, start, end, obc);
1697    }
1698
1699    public List<JournalArticle> search(
1700            long companyId, long groupId, String articleId, Double version,
1701            String title, String description, String content, String type,
1702            String structureId, String templateId, Date displayDateGT,
1703            Date displayDateLT, Boolean approved, Boolean expired,
1704            Date reviewDate, boolean andOperator, int start, int end,
1705            OrderByComparator obc)
1706        throws SystemException {
1707
1708        return journalArticleFinder.findByC_G_A_V_T_D_C_T_S_T_D_A_E_R(
1709            companyId, groupId, articleId, version, title, description, content,
1710            type, structureId, templateId, displayDateGT, displayDateLT,
1711            approved, expired, reviewDate, andOperator, start, end, obc);
1712    }
1713
1714    public List<JournalArticle> search(
1715            long companyId, long groupId, String articleId, Double version,
1716            String title, String description, String content, String type,
1717            String[] structureIds, String[] templateIds, Date displayDateGT,
1718            Date displayDateLT, Boolean approved, Boolean expired,
1719            Date reviewDate, boolean andOperator, int start, int end,
1720            OrderByComparator obc)
1721        throws SystemException {
1722
1723        return journalArticleFinder.findByC_G_A_V_T_D_C_T_S_T_D_A_E_R(
1724            companyId, groupId, articleId, version, title, description, content,
1725            type, structureIds, templateIds, displayDateGT, displayDateLT,
1726            approved, expired, reviewDate, andOperator, start, end, obc);
1727    }
1728
1729    public int searchCount(
1730            long companyId, long groupId, String keywords, Double version,
1731            String type, String structureId, String templateId,
1732            Date displayDateGT, Date displayDateLT, Boolean approved,
1733            Boolean expired, Date reviewDate)
1734        throws SystemException {
1735
1736        return journalArticleFinder.countByKeywords(
1737            companyId, groupId, keywords, version, type, structureId,
1738            templateId, displayDateGT, displayDateLT, approved, expired,
1739            reviewDate);
1740    }
1741
1742    public int searchCount(
1743            long companyId, long groupId, String articleId, Double version,
1744            String title, String description, String content, String type,
1745            String structureId, String templateId, Date displayDateGT,
1746            Date displayDateLT, Boolean approved, Boolean expired,
1747            Date reviewDate, boolean andOperator)
1748        throws SystemException {
1749
1750        return journalArticleFinder.countByC_G_A_V_T_D_C_T_S_T_D_A_E_R(
1751            companyId, groupId, articleId, version, title, description, content,
1752            type, structureId, templateId, displayDateGT, displayDateLT,
1753            approved, expired, reviewDate, andOperator);
1754    }
1755
1756    public int searchCount(
1757            long companyId, long groupId, String articleId, Double version,
1758            String title, String description, String content, String type,
1759            String[] structureIds, String[] templateIds, Date displayDateGT,
1760            Date displayDateLT, Boolean approved, Boolean expired,
1761            Date reviewDate, boolean andOperator)
1762        throws SystemException {
1763
1764        return journalArticleFinder.countByC_G_A_V_T_D_C_T_S_T_D_A_E_R(
1765            companyId, groupId, articleId, version, title, description, content,
1766            type, structureIds, templateIds, displayDateGT, displayDateLT,
1767            approved, expired, reviewDate, andOperator);
1768    }
1769
1770    public JournalArticle updateArticle(
1771            long userId, long groupId, String articleId, double version,
1772            boolean incrementVersion, String content)
1773        throws PortalException, SystemException {
1774
1775        User user = userPersistence.findByPrimaryKey(userId);
1776
1777        JournalArticle article = journalArticlePersistence.findByG_A_V(
1778            groupId, articleId, version);
1779
1780        Date displayDate = article.getDisplayDate();
1781
1782        int displayDateMonth = 0;
1783        int displayDateDay = 0;
1784        int displayDateYear = 0;
1785        int displayDateHour = 0;
1786        int displayDateMinute = 0;
1787
1788        if (displayDate != null) {
1789            Calendar displayCal = CalendarFactoryUtil.getCalendar(
1790                user.getTimeZone());
1791
1792            displayCal.setTime(displayDate);
1793
1794            displayDateMonth = displayCal.get(Calendar.MONTH);
1795            displayDateDay = displayCal.get(Calendar.DATE);
1796            displayDateYear = displayCal.get(Calendar.YEAR);
1797            displayDateHour = displayCal.get(Calendar.HOUR);
1798            displayDateMinute = displayCal.get(Calendar.MINUTE);
1799
1800            if (displayCal.get(Calendar.AM_PM) == Calendar.PM) {
1801                displayDateHour += 12;
1802            }
1803        }
1804
1805        Date expirationDate = article.getExpirationDate();
1806
1807        int expirationDateMonth = 0;
1808        int expirationDateDay = 0;
1809        int expirationDateYear = 0;
1810        int expirationDateHour = 0;
1811        int expirationDateMinute = 0;
1812        boolean neverExpire = true;
1813
1814        if (expirationDate != null) {
1815            Calendar expirationCal = CalendarFactoryUtil.getCalendar(
1816                user.getTimeZone());
1817
1818            expirationCal.setTime(expirationDate);
1819
1820            expirationDateMonth = expirationCal.get(Calendar.MONTH);
1821            expirationDateDay = expirationCal.get(Calendar.DATE);
1822            expirationDateYear = expirationCal.get(Calendar.YEAR);
1823            expirationDateHour = expirationCal.get(Calendar.HOUR);
1824            expirationDateMinute = expirationCal.get(Calendar.MINUTE);
1825            neverExpire = false;
1826
1827            if (expirationCal.get(Calendar.AM_PM) == Calendar.PM) {
1828                expirationDateHour += 12;
1829            }
1830        }
1831
1832        Date reviewDate = article.getReviewDate();
1833
1834        int reviewDateMonth = 0;
1835        int reviewDateDay = 0;
1836        int reviewDateYear = 0;
1837        int reviewDateHour = 0;
1838        int reviewDateMinute = 0;
1839        boolean neverReview = true;
1840
1841        if (reviewDate != null) {
1842            Calendar reviewCal = CalendarFactoryUtil.getCalendar(
1843                user.getTimeZone());
1844
1845            reviewCal.setTime(reviewDate);
1846
1847            reviewDateMonth = reviewCal.get(Calendar.MONTH);
1848            reviewDateDay = reviewCal.get(Calendar.DATE);
1849            reviewDateYear = reviewCal.get(Calendar.YEAR);
1850            reviewDateHour = reviewCal.get(Calendar.HOUR);
1851            reviewDateMinute = reviewCal.get(Calendar.MINUTE);
1852            neverReview = false;
1853
1854            if (reviewCal.get(Calendar.AM_PM) == Calendar.PM) {
1855                reviewDateHour += 12;
1856            }
1857        }
1858
1859        PortletPreferencesIds portletPreferencesIds = new PortletPreferencesIds(
1860            article.getCompanyId(), PortletKeys.PREFS_OWNER_ID_DEFAULT,
1861            PortletKeys.PREFS_OWNER_TYPE_LAYOUT, PortletKeys.PREFS_PLID_SHARED,
1862            PortletKeys.JOURNAL);
1863
1864        String[] tagsCategories = getTagsEntries(article);
1865        String[] tagsEntries = getTagsCategories(article);
1866
1867        ServiceContext serviceContext = new ServiceContext();
1868
1869        serviceContext.setPortletPreferencesIds(portletPreferencesIds);
1870        serviceContext.setTagsCategories(tagsCategories);
1871        serviceContext.setTagsEntries(tagsEntries);
1872
1873        return updateArticle(
1874            userId, groupId, articleId, version, incrementVersion,
1875            article.getTitle(), article.getDescription(), content,
1876            article.getType(), article.getStructureId(),
1877            article.getTemplateId(), displayDateMonth, displayDateDay,
1878            displayDateYear, displayDateHour, displayDateMinute,
1879            expirationDateMonth, expirationDateDay, expirationDateYear,
1880            expirationDateHour, expirationDateMinute, neverExpire,
1881            reviewDateMonth, reviewDateDay, reviewDateYear, reviewDateHour,
1882            reviewDateMinute, neverReview, article.getIndexable(),
1883            article.isSmallImage(), article.getSmallImageURL(), null, null,
1884            null, serviceContext);
1885    }
1886
1887    public JournalArticle updateArticle(
1888            long userId, long groupId, String articleId, double version,
1889            boolean incrementVersion, String title, String description,
1890            String content, String type, String structureId, String templateId,
1891            int displayDateMonth, int displayDateDay, int displayDateYear,
1892            int displayDateHour, int displayDateMinute, int expirationDateMonth,
1893            int expirationDateDay, int expirationDateYear,
1894            int expirationDateHour, int expirationDateMinute,
1895            boolean neverExpire, int reviewDateMonth, int reviewDateDay,
1896            int reviewDateYear, int reviewDateHour, int reviewDateMinute,
1897            boolean neverReview, boolean indexable, boolean smallImage,
1898            String smallImageURL, File smallFile, Map<String, byte[]> images,
1899            String articleURL, ServiceContext serviceContext)
1900        throws PortalException, SystemException {
1901
1902        // Article
1903
1904        User user = userPersistence.findByPrimaryKey(userId);
1905        articleId = articleId.trim().toUpperCase();
1906
1907        Date displayDate = PortalUtil.getDate(
1908            displayDateMonth, displayDateDay, displayDateYear,
1909            displayDateHour, displayDateMinute, user.getTimeZone(),
1910            new ArticleDisplayDateException());
1911
1912        Date expirationDate = null;
1913
1914        if (!neverExpire) {
1915            expirationDate = PortalUtil.getDate(
1916                expirationDateMonth, expirationDateDay, expirationDateYear,
1917                expirationDateHour, expirationDateMinute, user.getTimeZone(),
1918                new ArticleExpirationDateException());
1919        }
1920
1921        Date reviewDate = null;
1922
1923        if (!neverReview) {
1924            reviewDate = PortalUtil.getDate(
1925                reviewDateMonth, reviewDateDay, reviewDateYear, reviewDateHour,
1926                reviewDateMinute, user.getTimeZone(),
1927                new ArticleReviewDateException());
1928        }
1929
1930        byte[] smallBytes = null;
1931
1932        try {
1933            smallBytes = FileUtil.getBytes(smallFile);
1934        }
1935        catch (IOException ioe) {
1936        }
1937
1938        Date now = new Date();
1939
1940        validate(
1941            groupId, title, content, type, structureId, templateId, smallImage,
1942            smallImageURL, smallFile, smallBytes);
1943
1944        JournalArticle oldArticle = journalArticlePersistence.findByG_A_V(
1945            groupId, articleId, version);
1946
1947        JournalArticle article = null;
1948
1949        if (incrementVersion) {
1950            double latestVersion = getLatestVersion(groupId, articleId);
1951
1952            long id = counterLocalService.increment();
1953
1954            article = journalArticlePersistence.create(id);
1955
1956            article.setResourcePrimKey(oldArticle.getResourcePrimKey());
1957            article.setGroupId(oldArticle.getGroupId());
1958            article.setCompanyId(user.getCompanyId());
1959            article.setUserId(user.getUserId());
1960            article.setUserName(user.getFullName());
1961            article.setCreateDate(serviceContext.getModifiedDate(now));
1962            article.setArticleId(articleId);
1963            article.setVersion(MathUtil.format(latestVersion + 0.1, 1, 1));
1964            article.setSmallImageId(oldArticle.getSmallImageId());
1965        }
1966        else {
1967            article = oldArticle;
1968        }
1969
1970        content = format(
1971            groupId, articleId, article.getVersion(), incrementVersion, content,
1972            structureId, images);
1973
1974        boolean approved = oldArticle.isApproved();
1975
1976        if (incrementVersion) {
1977            approved = false;
1978        }
1979
1980        article.setModifiedDate(serviceContext.getModifiedDate(now));
1981        article.setTitle(title);
1982        article.setUrlTitle(
1983            getUniqueUrlTitle(article.getId(), groupId, articleId, title));
1984        article.setDescription(description);
1985        article.setContent(content);
1986        article.setType(type);
1987        article.setStructureId(structureId);
1988        article.setTemplateId(templateId);
1989        article.setDisplayDate(displayDate);
1990        article.setApproved(approved);
1991
1992        if ((expirationDate == null) || expirationDate.after(now)) {
1993            article.setExpired(false);
1994        }
1995        else {
1996            article.setExpired(true);
1997        }
1998
1999        article.setExpirationDate(expirationDate);
2000        article.setReviewDate(reviewDate);
2001        article.setIndexable(indexable);
2002        article.setSmallImage(smallImage);
2003
2004        if (article.getSmallImageId() == 0) {
2005            article.setSmallImageId(counterLocalService.increment());
2006        }
2007
2008        article.setSmallImageURL(smallImageURL);
2009
2010        journalArticlePersistence.update(article, false);
2011
2012        updateUrlTitles(groupId, articleId, article.getUrlTitle());
2013
2014        // Expando
2015
2016        ExpandoBridge expandoBridge = article.getExpandoBridge();
2017
2018        expandoBridge.setAttributes(serviceContext);
2019
2020        // Small image
2021
2022        saveImages(
2023            smallImage, article.getSmallImageId(), smallFile, smallBytes);
2024
2025        // Tags
2026
2027        String[] tagsCategories = serviceContext.getTagsCategories();
2028        String[] tagsEntries = serviceContext.getTagsEntries();
2029
2030        updateTagsAsset(userId, article, tagsCategories, tagsEntries);
2031
2032        // Email
2033
2034        PortletPreferences preferences =
2035            ServiceContextUtil.getPortletPreferences(serviceContext);
2036
2037        if (incrementVersion) {
2038            try {
2039                sendEmail(article, articleURL, preferences, "requested");
2040            }
2041            catch (IOException ioe) {
2042                throw new SystemException(ioe);
2043            }
2044        }
2045
2046        // Indexer
2047
2048        reIndex(article);
2049
2050        return article;
2051    }
2052
2053    public JournalArticle updateContent(
2054            long groupId, String articleId, double version, String content)
2055        throws PortalException, SystemException {
2056
2057        JournalArticle article = journalArticlePersistence.findByG_A_V(
2058            groupId, articleId, version);
2059
2060        article.setContent(content);
2061
2062        journalArticlePersistence.update(article, false);
2063
2064        return article;
2065    }
2066
2067    public void updateTagsAsset(
2068            long userId, JournalArticle article, String[] tagsCategories,
2069            String[] tagsEntries)
2070        throws PortalException, SystemException {
2071
2072        // Get the earliest display date and latest expiration date among
2073        // all article versions
2074
2075        Date[] dateInterval = getDateInterval(
2076            article.getGroupId(), article.getArticleId(),
2077            article.getDisplayDate(), article.getExpirationDate());
2078
2079        Date displayDate = dateInterval[0];
2080        Date expirationDate = dateInterval[1];
2081
2082        boolean visible = article.getApproved();
2083
2084        if (!visible &&
2085            (article.getVersion() != JournalArticleImpl.DEFAULT_VERSION)) {
2086
2087            int approvedArticlesCount =
2088                journalArticlePersistence.countByG_A_A(
2089                    article.getGroupId(), article.getArticleId(), true);
2090
2091            if (approvedArticlesCount > 0) {
2092                visible = true;
2093            }
2094        }
2095
2096        tagsAssetLocalService.updateAsset(
2097            userId, article.getGroupId(), JournalArticle.class.getName(),
2098            article.getResourcePrimKey(), tagsCategories, tagsEntries,
2099            visible, null, null, displayDate, expirationDate,
2100            ContentTypes.TEXT_HTML, article.getTitle(),
2101            article.getDescription(), null, null, 0, 0, null, false);
2102    }
2103
2104    protected void checkStructure(Document contentDoc, Element root)
2105        throws PortalException {
2106
2107        for (Element el : root.elements()) {
2108            checkStructureField(el, contentDoc);
2109
2110            checkStructure(contentDoc, el);
2111        }
2112    }
2113
2114    protected void checkStructure(JournalArticle article)
2115        throws DocumentException, PortalException, SystemException {
2116
2117        JournalStructure structure = journalStructurePersistence.findByG_S(
2118            article.getGroupId(), article.getStructureId());
2119
2120        String content = GetterUtil.getString(article.getContent());
2121
2122        Document contentDoc = SAXReaderUtil.read(content);
2123        Document xsdDoc = SAXReaderUtil.read(structure.getXsd());
2124
2125        try {
2126            checkStructure(contentDoc, xsdDoc.getRootElement());
2127        }
2128        catch (StructureXsdException sxsde) {
2129            long groupId = article.getGroupId();
2130            String articleId = article.getArticleId();
2131            double version = article.getVersion();
2132
2133            if (_log.isWarnEnabled()) {
2134                _log.warn(
2135                    "Article {groupId=" + groupId + ", articleId=" +
2136                        articleId + ", version=" + version +
2137                            "} has content that does not match its " +
2138                                "structure: " + sxsde.getMessage());
2139            }
2140        }
2141    }
2142
2143    protected void checkStructureField(Element el, Document contentDoc)
2144        throws PortalException {
2145
2146        StringBuilder elPath = new StringBuilder();
2147
2148        elPath.append(el.attributeValue("name"));
2149
2150        Element elParent = el.getParent();
2151
2152        for (;;) {
2153            if ((elParent == null) ||
2154                (elParent.getName().equals("root"))) {
2155
2156                break;
2157            }
2158
2159            elPath.insert(
2160                0, elParent.attributeValue("name") + StringPool.COMMA);
2161
2162            elParent = elParent.getParent();
2163        }
2164
2165        String[] elPathNames = StringUtil.split(elPath.toString());
2166
2167        Element contentEl = contentDoc.getRootElement();
2168
2169        for (int i = 0; i < elPathNames.length; i++) {
2170            boolean foundEl = false;
2171
2172            for (Element tempEl : contentEl.elements()) {
2173                if (elPathNames[i].equals(
2174                        tempEl.attributeValue("name", StringPool.BLANK))) {
2175
2176                    contentEl = tempEl;
2177                    foundEl = true;
2178
2179                    break;
2180                }
2181            }
2182
2183            if (!foundEl) {
2184                String elType = contentEl.attributeValue(
2185                    "type", StringPool.BLANK);
2186
2187                if (!elType.equals("list") && !elType.equals("multi-list")) {
2188                    throw new StructureXsdException(elPath.toString());
2189                }
2190
2191                break;
2192            }
2193        }
2194    }
2195
2196    protected void copyArticleImages(
2197            JournalArticle oldArticle, JournalArticle newArticle)
2198        throws Exception {
2199
2200        Document contentDoc = SAXReaderUtil.read(oldArticle.getContent());
2201
2202        XPath xpathSelector = SAXReaderUtil.createXPath(
2203            "//dynamic-element[@type='image']");
2204
2205        List<Node> imageNodes = xpathSelector.selectNodes(contentDoc);
2206
2207        for (Node imageNode : imageNodes) {
2208            Element imageEl = (Element)imageNode;
2209
2210            String instanceId = imageEl.attributeValue("instance-id");
2211            String name = imageEl.attributeValue("name");
2212
2213            List<Element> dynamicContentEls = imageEl.elements(
2214                "dynamic-content");
2215
2216            for (Element dynamicContentEl : dynamicContentEls) {
2217                long imageId = GetterUtil.getLong(
2218                    dynamicContentEl.attributeValue("id"));
2219                String languageId = dynamicContentEl.attributeValue(
2220                    "language-id");
2221
2222                Image oldImage = null;
2223
2224                try {
2225                    oldImage = imageLocalService.getImage(imageId);
2226                }
2227                catch (NoSuchImageException nsie) {
2228                    continue;
2229                }
2230
2231                imageId = journalArticleImageLocalService.getArticleImageId(
2232                    newArticle.getGroupId(), newArticle.getArticleId(),
2233                    newArticle.getVersion(), instanceId, name, languageId);
2234
2235                imageLocalService.updateImage(imageId, oldImage.getTextObj());
2236
2237                String elContent =
2238                    "/image/journal/article?img_id=" + imageId + "&t=" +
2239                        ImageServletTokenUtil.getToken(imageId);
2240
2241                dynamicContentEl.setText(elContent);
2242                dynamicContentEl.addAttribute("id", String.valueOf(imageId));
2243            }
2244        }
2245
2246        newArticle.setContent(contentDoc.formattedString());
2247    }
2248
2249    protected void format(
2250            long groupId, String articleId, double version,
2251            boolean incrementVersion, Element root, Map<String, byte[]> images)
2252        throws PortalException, SystemException {
2253
2254        for (Element el : root.elements()) {
2255            String elInstanceId = el.attributeValue(
2256                "instance-id", StringPool.BLANK);
2257            String elName = el.attributeValue("name", StringPool.BLANK);
2258            String elType = el.attributeValue("type", StringPool.BLANK);
2259
2260            if (elType.equals("image")) {
2261                formatImage(
2262                    groupId, articleId, version, incrementVersion, el,
2263                    elInstanceId, elName, images);
2264            }
2265            /*else if (elType.equals("text_area")) {
2266                Element dynamicContent = el.element("dynamic-content");
2267
2268                String text = dynamicContent.getText();
2269
2270                // LEP-1594
2271
2272                try {
2273                    text = ParserUtils.trimTags(
2274                        text, new String[] {"script"}, false, true);
2275                }
2276                catch (ParserException pe) {
2277                    text = pe.getLocalizedMessage();
2278                }
2279                catch (UnsupportedEncodingException uee) {
2280                    text = uee.getLocalizedMessage();
2281                }
2282
2283                dynamicContent.setText(text);
2284            }*/
2285
2286            format(groupId, articleId, version, incrementVersion, el, images);
2287        }
2288    }
2289
2290    protected String format(
2291            long groupId, String articleId, double version,
2292            boolean incrementVersion, String content, String structureId,
2293            Map<String, byte[]> images)
2294        throws PortalException, SystemException {
2295
2296        if (Validator.isNotNull(structureId)) {
2297            Document doc = null;
2298
2299            try {
2300                doc = SAXReaderUtil.read(content);
2301
2302                Element root = doc.getRootElement();
2303
2304                format(
2305                    groupId, articleId, version, incrementVersion, root,
2306                    images);
2307
2308                content = JournalUtil.formatXML(doc);
2309            }
2310            catch (DocumentException de) {
2311                _log.error(de);
2312            }
2313            catch (IOException ioe) {
2314                _log.error(ioe);
2315            }
2316        }
2317
2318        content = HtmlUtil.replaceMsWordCharacters(content);
2319
2320        return content;
2321    }
2322
2323    protected void formatImage(
2324            long groupId, String articleId, double version,
2325            boolean incrementVersion, Element el, String elInstanceId,
2326            String elName, Map<String, byte[]> images)
2327        throws PortalException, SystemException {
2328
2329        List<Element> imageContents = el.elements("dynamic-content");
2330
2331        for (Element dynamicContent : imageContents) {
2332            String elLanguage = dynamicContent.attributeValue(
2333                "language-id", StringPool.BLANK);
2334
2335            if (!elLanguage.equals(StringPool.BLANK)) {
2336                elLanguage = "_" + elLanguage;
2337            }
2338
2339            long imageId =
2340                journalArticleImageLocalService.getArticleImageId(
2341                    groupId, articleId, version, elInstanceId, elName,
2342                    elLanguage);
2343
2344            double oldVersion = MathUtil.format(version - 0.1, 1, 1);
2345
2346            long oldImageId = 0;
2347
2348            if ((oldVersion >= 1) && incrementVersion) {
2349                oldImageId =
2350                    journalArticleImageLocalService.getArticleImageId(
2351                        groupId, articleId, oldVersion, elInstanceId, elName,
2352                        elLanguage);
2353            }
2354
2355            String elContent =
2356                "/image/journal/article?img_id=" + imageId + "&t=" +
2357                    ImageServletTokenUtil.getToken(imageId);
2358
2359            if (dynamicContent.getText().equals("delete")) {
2360                dynamicContent.setText(StringPool.BLANK);
2361
2362                imageLocalService.deleteImage(imageId);
2363
2364                String defaultElLanguage = "";
2365
2366                if (!Validator.isNotNull(elLanguage)) {
2367                    defaultElLanguage =
2368                        "_" + LocaleUtil.toLanguageId(LocaleUtil.getDefault());
2369                }
2370
2371                long defaultImageId =
2372                    journalArticleImageLocalService.getArticleImageId(
2373                        groupId, articleId, version, elInstanceId, elName,
2374                        defaultElLanguage);
2375
2376                imageLocalService.deleteImage(defaultImageId);
2377
2378                continue;
2379            }
2380
2381            byte[] bytes = images.get(elInstanceId + "_" + elName + elLanguage);
2382
2383            if (bytes != null && (bytes.length > 0)) {
2384                dynamicContent.setText(elContent);
2385                dynamicContent.addAttribute("id", String.valueOf(imageId));
2386
2387                imageLocalService.updateImage(imageId, bytes);
2388
2389                continue;
2390            }
2391
2392            if ((version > JournalArticleImpl.DEFAULT_VERSION) &&
2393                (incrementVersion)) {
2394
2395                Image oldImage = null;
2396
2397                if (oldImageId > 0) {
2398                    oldImage = imageLocalService.getImage(oldImageId);
2399                }
2400
2401                if (oldImage != null) {
2402                    dynamicContent.setText(elContent);
2403                    dynamicContent.addAttribute("id", String.valueOf(imageId));
2404
2405                    bytes = oldImage.getTextObj();
2406
2407                    imageLocalService.updateImage(imageId, bytes);
2408                }
2409
2410                continue;
2411            }
2412
2413            Image image = imageLocalService.getImage(imageId);
2414
2415            if (image != null) {
2416                dynamicContent.setText(elContent);
2417                dynamicContent.addAttribute("id", String.valueOf(imageId));
2418
2419                continue;
2420            }
2421
2422            long contentImageId = GetterUtil.getLong(HttpUtil.getParameter(
2423                dynamicContent.getText(), "img_id"));
2424
2425            if (contentImageId <= 0) {
2426                contentImageId = GetterUtil.getLong(HttpUtil.getParameter(
2427                    dynamicContent.getText(), "img_id", false));
2428            }
2429
2430            if (contentImageId > 0) {
2431                image = imageLocalService.getImage(contentImageId);
2432
2433                if (image != null) {
2434                    dynamicContent.addAttribute(
2435                        "id", String.valueOf(contentImageId));
2436
2437                    continue;
2438                }
2439            }
2440
2441            String defaultElLanguage = "";
2442
2443            if (!Validator.isNotNull(elLanguage)) {
2444                defaultElLanguage =
2445                    "_" + LocaleUtil.toLanguageId(LocaleUtil.getDefault());
2446            }
2447
2448            long defaultImageId =
2449                journalArticleImageLocalService.getArticleImageId(
2450                    groupId, articleId, version, elInstanceId, elName,
2451                    defaultElLanguage);
2452
2453            Image defaultImage = imageLocalService.getImage(defaultImageId);
2454
2455            if (defaultImage != null) {
2456                dynamicContent.setText(elContent);
2457                dynamicContent.addAttribute(
2458                    "id", String.valueOf(defaultImageId));
2459
2460                bytes = defaultImage.getTextObj();
2461
2462                imageLocalService.updateImage(defaultImageId, bytes);
2463
2464                continue;
2465            }
2466
2467            dynamicContent.setText(StringPool.BLANK);
2468        }
2469    }
2470
2471    protected Date[] getDateInterval(
2472            long groupId, String articleId, Date earliestDisplayDate,
2473            Date latestExpirationDate)
2474        throws SystemException {
2475
2476        Date[] dateInterval = new Date[2];
2477
2478        List<JournalArticle> articles = journalArticlePersistence.findByG_A_A(
2479            groupId, articleId, true);
2480
2481        boolean expiringArticle = true;
2482
2483        if (latestExpirationDate == null) {
2484            expiringArticle = false;
2485        }
2486
2487        for (JournalArticle article : articles) {
2488            if ((earliestDisplayDate == null) ||
2489                ((article.getDisplayDate() != null) &&
2490                 earliestDisplayDate.after(article.getDisplayDate()))) {
2491
2492                earliestDisplayDate = article.getDisplayDate();
2493            }
2494
2495            if (expiringArticle &&
2496                ((latestExpirationDate == null) ||
2497                 ((article.getExpirationDate() != null) &&
2498                  latestExpirationDate.before(article.getExpirationDate())))) {
2499
2500                latestExpirationDate = article.getExpirationDate();
2501            }
2502
2503            if (expiringArticle && (article.getExpirationDate() == null)) {
2504                latestExpirationDate = null;
2505                expiringArticle = false;
2506            }
2507        }
2508
2509        dateInterval[0] = earliestDisplayDate;
2510        dateInterval[1] = latestExpirationDate;
2511
2512        return dateInterval;
2513    }
2514
2515    protected String[] getTagsCategories(JournalArticle article)
2516        throws SystemException {
2517
2518        List<TagsEntry> tagsEntries = tagsEntryLocalService.getEntries(
2519            JournalArticle.class.getName(), article.getPrimaryKey(), false);
2520
2521        return StringUtil.split(ListUtil.toString(tagsEntries, "name"));
2522    }
2523
2524    protected String[] getTagsEntries(JournalArticle article)
2525        throws SystemException {
2526
2527        List<TagsEntry> tagsEntries = tagsEntryLocalService.getEntries(
2528            JournalArticle.class.getName(), article.getPrimaryKey(), true);
2529
2530        return StringUtil.split(ListUtil.toString(tagsEntries, "name"));
2531    }
2532
2533    protected String getUniqueUrlTitle(
2534            long id, long groupId, String articleId, String title)
2535        throws PortalException, SystemException {
2536
2537        String urlTitle = JournalUtil.getUrlTitle(id, title);
2538
2539        String newUrlTitle = urlTitle;
2540
2541        for (int i = 1;; i++) {
2542            JournalArticle article = null;
2543
2544            try {
2545                article = getArticleByUrlTitle(groupId, newUrlTitle);
2546            }
2547            catch (NoSuchArticleException nsae) {
2548            }
2549
2550            if ((article == null) || article.getArticleId().equals(articleId)) {
2551                break;
2552            }
2553            else {
2554                newUrlTitle = urlTitle + StringPool.DASH + i;
2555            }
2556        }
2557
2558        return newUrlTitle;
2559    }
2560
2561    protected void reIndexArticles(long companyId) throws SystemException {
2562        int count = journalArticlePersistence.countByCompanyId(companyId);
2563
2564        int pages = count / Indexer.DEFAULT_INTERVAL;
2565
2566        for (int i = 0; i <= pages; i++) {
2567            int start = (i * Indexer.DEFAULT_INTERVAL);
2568            int end = start + Indexer.DEFAULT_INTERVAL;
2569
2570            reIndexArticles(companyId, start, end);
2571        }
2572    }
2573
2574    protected void reIndexArticles(long companyId, int start, int end)
2575        throws SystemException {
2576
2577        List<JournalArticle> articles =
2578            journalArticlePersistence.findByCompanyId(
2579                companyId, start, end, new ArticleIDComparator(true));
2580
2581        for (JournalArticle article : articles) {
2582            reIndex(article);
2583        }
2584    }
2585
2586    protected void saveImages(
2587            boolean smallImage, long smallImageId, File smallFile,
2588            byte[] smallBytes)
2589        throws PortalException, SystemException {
2590
2591        if (smallImage) {
2592            if ((smallFile != null) && (smallBytes != null)) {
2593                imageLocalService.updateImage(smallImageId, smallBytes);
2594            }
2595        }
2596        else {
2597            imageLocalService.deleteImage(smallImageId);
2598        }
2599    }
2600
2601    protected void sendEmail(
2602            JournalArticle article, String articleURL,
2603            PortletPreferences preferences, String emailType)
2604        throws IOException, PortalException, SystemException {
2605
2606        if (preferences == null) {
2607            return;
2608        }
2609        else if (emailType.equals("denied") &&
2610            JournalUtil.getEmailArticleApprovalDeniedEnabled(preferences)) {
2611        }
2612        else if (emailType.equals("granted") &&
2613                 JournalUtil.getEmailArticleApprovalGrantedEnabled(
2614                    preferences)) {
2615        }
2616        else if (emailType.equals("requested") &&
2617                 JournalUtil.getEmailArticleApprovalRequestedEnabled(
2618                    preferences)) {
2619        }
2620        else if (emailType.equals("review") &&
2621                 JournalUtil.getEmailArticleReviewEnabled(preferences)) {
2622        }
2623        else {
2624            return;
2625        }
2626
2627        Company company = companyPersistence.findByPrimaryKey(
2628            article.getCompanyId());
2629
2630        User user = userPersistence.findByPrimaryKey(article.getUserId());
2631
2632        articleURL +=
2633            "&groupId=" + article.getGroupId() + "&articleId=" +
2634                article.getArticleId() + "&version=" + article.getVersion();
2635
2636        String portletName = PortalUtil.getPortletTitle(
2637            PortletKeys.JOURNAL, user);
2638
2639        String fromName = JournalUtil.getEmailFromName(preferences);
2640        String fromAddress = JournalUtil.getEmailFromAddress(preferences);
2641
2642        String toName = user.getFullName();
2643        String toAddress = user.getEmailAddress();
2644
2645        if (emailType.equals("requested") ||
2646            emailType.equals("review")) {
2647
2648            String tempToName = fromName;
2649            String tempToAddress = fromAddress;
2650
2651            fromName = toName;
2652            fromAddress = toAddress;
2653
2654            toName = tempToName;
2655            toAddress = tempToAddress;
2656        }
2657
2658        String subject = null;
2659        String body = null;
2660
2661        if (emailType.equals("denied")) {
2662            subject =
2663                JournalUtil.getEmailArticleApprovalDeniedSubject(preferences);
2664            body = JournalUtil.getEmailArticleApprovalDeniedBody(preferences);
2665        }
2666        else if (emailType.equals("granted")) {
2667            subject =
2668                JournalUtil.getEmailArticleApprovalGrantedSubject(preferences);
2669            body = JournalUtil.getEmailArticleApprovalGrantedBody(preferences);
2670        }
2671        else if (emailType.equals("requested")) {
2672            subject =
2673                JournalUtil.getEmailArticleApprovalRequestedSubject(
2674                preferences);
2675            body = JournalUtil.getEmailArticleApprovalRequestedBody(
2676                preferences);
2677        }
2678        else if (emailType.equals("review")) {
2679            subject = JournalUtil.getEmailArticleReviewSubject(preferences);
2680            body = JournalUtil.getEmailArticleReviewBody(preferences);
2681        }
2682
2683        subject = StringUtil.replace(
2684            subject,
2685            new String[] {
2686                "[$ARTICLE_ID$]",
2687                "[$ARTICLE_TITLE$]",
2688                "[$ARTICLE_URL$]",
2689                "[$ARTICLE_VERSION$]",
2690                "[$FROM_ADDRESS$]",
2691                "[$FROM_NAME$]",
2692                "[$PORTAL_URL$]",
2693                "[$PORTLET_NAME$]",
2694                "[$TO_ADDRESS$]",
2695                "[$TO_NAME$]"
2696            },
2697            new String[] {
2698                article.getArticleId(),
2699                article.getTitle(),
2700                articleURL,
2701                String.valueOf(article.getVersion()),
2702                fromAddress,
2703                fromName,
2704                company.getVirtualHost(),
2705                portletName,
2706                toAddress,
2707                toName,
2708            });
2709
2710        body = StringUtil.replace(
2711            body,
2712            new String[] {
2713                "[$ARTICLE_ID$]",
2714                "[$ARTICLE_TITLE$]",
2715                "[$ARTICLE_URL$]",
2716                "[$ARTICLE_VERSION$]",
2717                "[$FROM_ADDRESS$]",
2718                "[$FROM_NAME$]",
2719                "[$PORTAL_URL$]",
2720                "[$PORTLET_NAME$]",
2721                "[$TO_ADDRESS$]",
2722                "[$TO_NAME$]"
2723            },
2724            new String[] {
2725                article.getArticleId(),
2726                article.getTitle(),
2727                articleURL,
2728                String.valueOf(article.getVersion()),
2729                fromAddress,
2730                fromName,
2731                company.getVirtualHost(),
2732                portletName,
2733                toAddress,
2734                toName,
2735            });
2736
2737        InternetAddress from = new InternetAddress(fromAddress, fromName);
2738
2739        InternetAddress to = new InternetAddress(toAddress, toName);
2740
2741        MailMessage message = new MailMessage(from, to, subject, body, true);
2742
2743        mailService.sendEmail(message);
2744    }
2745
2746    protected void updateUrlTitles(
2747            long groupId, String articleId, String urlTitle)
2748        throws SystemException {
2749
2750        List<JournalArticle> articles = journalArticlePersistence.findByG_A(
2751            groupId, articleId);
2752
2753        for (JournalArticle article : articles) {
2754            if (!article.getUrlTitle().equals(urlTitle)) {
2755                article.setUrlTitle(urlTitle);
2756
2757                journalArticlePersistence.update(article, false);
2758            }
2759        }
2760    }
2761
2762    protected void validate(
2763            long groupId, String articleId, boolean autoArticleId,
2764            double version, String title, String content, String type,
2765            String structureId, String templateId, boolean smallImage,
2766            String smallImageURL, File smallFile, byte[] smallBytes)
2767        throws PortalException, SystemException {
2768
2769        if (!autoArticleId) {
2770            validate(articleId);
2771
2772            JournalArticle article = journalArticlePersistence.fetchByG_A_V(
2773                groupId, articleId, version);
2774
2775            if (article != null) {
2776                throw new DuplicateArticleIdException();
2777            }
2778        }
2779
2780        validate(
2781            groupId, title, content, type, structureId, templateId,
2782            smallImage, smallImageURL, smallFile, smallBytes);
2783    }
2784
2785    protected void validate(
2786            long groupId, String title, String content, String type,
2787            String structureId, String templateId, boolean smallImage,
2788            String smallImageURL, File smallFile, byte[] smallBytes)
2789        throws PortalException, SystemException {
2790
2791        if (Validator.isNull(title)) {
2792            throw new ArticleTitleException();
2793        }
2794        else if (Validator.isNull(content)) {
2795            throw new ArticleContentException();
2796        }
2797        else if (Validator.isNull(type)) {
2798            throw new ArticleTypeException();
2799        }
2800
2801        if (Validator.isNotNull(structureId)) {
2802            journalStructurePersistence.findByG_S(groupId, structureId);
2803
2804            JournalTemplate template = journalTemplatePersistence.findByG_T(
2805                groupId, templateId);
2806
2807            if (!template.getStructureId().equals(structureId)) {
2808                throw new NoSuchTemplateException();
2809            }
2810        }
2811
2812        String[] imageExtensions = PrefsPropsUtil.getStringArray(
2813            PropsKeys.JOURNAL_IMAGE_EXTENSIONS, StringPool.COMMA);
2814
2815        if (smallImage && Validator.isNull(smallImageURL) &&
2816            smallFile != null && smallBytes != null) {
2817
2818            String smallImageName = smallFile.getName();
2819
2820            if (smallImageName != null) {
2821                boolean validSmallImageExtension = false;
2822
2823                for (int i = 0; i < imageExtensions.length; i++) {
2824                    if (StringPool.STAR.equals(imageExtensions[i]) ||
2825                        StringUtil.endsWith(
2826                            smallImageName, imageExtensions[i])) {
2827
2828                        validSmallImageExtension = true;
2829
2830                        break;
2831                    }
2832                }
2833
2834                if (!validSmallImageExtension) {
2835                    throw new ArticleSmallImageNameException(smallImageName);
2836                }
2837            }
2838
2839            long smallImageMaxSize = PrefsPropsUtil.getLong(
2840                PropsKeys.JOURNAL_IMAGE_SMALL_MAX_SIZE);
2841
2842            if ((smallImageMaxSize > 0) &&
2843                ((smallBytes == null) ||
2844                    (smallBytes.length > smallImageMaxSize))) {
2845
2846                throw new ArticleSmallImageSizeException();
2847            }
2848        }
2849    }
2850
2851    protected void validate(String articleId) throws PortalException {
2852        if ((Validator.isNull(articleId)) ||
2853            (articleId.indexOf(StringPool.SPACE) != -1)) {
2854
2855            throw new ArticleIdException();
2856        }
2857    }
2858
2859    private static final String _TOKEN_PAGE_BREAK = PropsUtil.get(
2860        PropsKeys.JOURNAL_ARTICLE_TOKEN_PAGE_BREAK);
2861
2862    private static Log _log = LogFactoryUtil.getLog(
2863        JournalArticleLocalServiceImpl.class);
2864
2865}