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