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