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