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