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