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