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