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