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