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         tokens.put(
937             "article_resource_pk",
938             String.valueOf(article.getResourcePrimKey()));
939 
940         String xml = article.getContent();
941 
942         try {
943             Document doc = null;
944 
945             Element root = null;
946 
947             if (article.isTemplateDriven()) {
948                 SAXReader reader = new SAXReader();
949 
950                 doc = reader.read(new StringReader(xml));
951 
952                 root = doc.getRootElement();
953 
954                 Document request = null;
955 
956                 if (Validator.isNotNull(xmlRequest)) {
957                     request = reader.read(new StringReader(xmlRequest));
958                 }
959 
960                 List pages = root.elements("page");
961 
962                 if (pages.size() > 0) {
963                     pageFlow = true;
964 
965                     String targetPage = request.valueOf(
966                         "/request/parameters/parameter[name='targetPage']/" +
967                             "value");
968 
969                     Element pageEl = null;
970 
971                     if (Validator.isNotNull(targetPage)) {
972                         XPath xpathSelector = DocumentHelper.createXPath(
973                             "/root/page[@id = '" + targetPage + "']");
974 
975                         pageEl = (Element)xpathSelector.selectSingleNode(doc);
976                     }
977 
978                     DocumentFactory docFactory = DocumentFactory.getInstance();
979 
980                     if (pageEl != null) {
981                         doc = docFactory.createDocument(pageEl);
982 
983                         root = doc.getRootElement();
984 
985                         numberOfPages = pages.size();
986                     }
987                     else {
988                         if (page > pages.size()) {
989                             page = 1;
990                         }
991 
992                         pageEl = (Element)pages.get(page - 1);
993 
994                         doc = docFactory.createDocument(pageEl);
995 
996                         root = doc.getRootElement();
997 
998                         numberOfPages = pages.size();
999                         paginate = true;
1000                    }
1001                }
1002
1003                if (request != null) {
1004                    root.add(request.getRootElement().createCopy());
1005                }
1006
1007                JournalUtil.addAllReservedEls(root, tokens, article);
1008
1009                xml = JournalUtil.formatXML(doc);
1010            }
1011        }
1012        catch (DocumentException de) {
1013            throw new SystemException(de);
1014        }
1015        catch (IOException ioe) {
1016            throw new SystemException(ioe);
1017        }
1018
1019        try {
1020            if (_log.isDebugEnabled()) {
1021                _log.debug(
1022                    "Transforming " + articleId + " " + version + " " +
1023                        languageId);
1024            }
1025
1026            String script = null;
1027            String langType = null;
1028
1029            if (article.isTemplateDriven()) {
1030
1031                // Try with specified template first. If a template is not
1032                // specified, use the default one. If the specified template
1033                // does not exit, use the default one. If the default one does
1034                // not exist, throw an exception.
1035
1036                String defaultTemplateId = article.getTemplateId();
1037
1038                if (Validator.isNull(templateId)) {
1039                    templateId = defaultTemplateId;
1040                }
1041
1042                JournalTemplate template = null;
1043
1044                try {
1045                    template = journalTemplatePersistence.findByG_T(
1046                        groupId, templateId);
1047                }
1048                catch (NoSuchTemplateException nste) {
1049                    if (!defaultTemplateId.equals(templateId)) {
1050                        template = journalTemplatePersistence.findByG_T(
1051                            groupId, defaultTemplateId);
1052                    }
1053                    else {
1054                        throw nste;
1055                    }
1056                }
1057
1058                script = template.getXsl();
1059                langType = template.getLangType();
1060                cacheable = template.isCacheable();
1061            }
1062
1063            content = JournalUtil.transform(
1064                tokens, languageId, xml, script, langType);
1065
1066            if (!pageFlow) {
1067                String[] pieces = StringUtil.split(content, _TOKEN_PAGE_BREAK);
1068
1069                if (pieces.length > 1) {
1070                    if (page > pieces.length) {
1071                        page = 1;
1072                    }
1073
1074                    content = pieces[page - 1];
1075                    numberOfPages = pieces.length;
1076                    paginate = true;
1077                }
1078            }
1079        }
1080        catch (Exception e) {
1081            throw new SystemException(e);
1082        }
1083
1084        return new JournalArticleDisplayImpl(
1085            article.getId(), article.getResourcePrimKey(), article.getGroupId(),
1086            article.getUserId(), article.getArticleId(), article.getVersion(),
1087            article.getTitle(), article.getDescription(),
1088            article.getAvailableLocales(), content, article.getType(),
1089            article.getStructureId(), templateId, article.isSmallImage(),
1090            article.getSmallImageId(), article.getSmallImageURL(),
1091            numberOfPages, page, paginate, cacheable);
1092    }
1093
1094    public List getArticles() throws SystemException {
1095        return journalArticlePersistence.findAll();
1096    }
1097
1098    public List getArticles(long groupId) throws SystemException {
1099        return journalArticlePersistence.findByGroupId(groupId);
1100    }
1101
1102    public List getArticles(long groupId, int begin, int end)
1103        throws SystemException {
1104
1105        return journalArticlePersistence.findByGroupId(groupId, begin, end);
1106    }
1107
1108    public List getArticles(
1109            long groupId, int begin, int end, OrderByComparator obc)
1110        throws SystemException {
1111
1112        return journalArticlePersistence.findByGroupId(
1113            groupId, begin, end, obc);
1114    }
1115
1116    public List getArticlesBySmallImageId(long smallImageId)
1117        throws SystemException {
1118
1119        return journalArticlePersistence.findBySmallImageId(smallImageId);
1120    }
1121
1122    public int getArticlesCount(long groupId) throws SystemException {
1123        return journalArticlePersistence.countByGroupId(groupId);
1124    }
1125
1126    public JournalArticle getDisplayArticle(long groupId, String articleId)
1127        throws PortalException, SystemException {
1128
1129        List articles = journalArticlePersistence.findByG_A_A(
1130            groupId, articleId, true);
1131
1132        if (articles.size() == 0) {
1133            throw new NoSuchArticleException();
1134        }
1135
1136        Collections.sort(articles, new ArticleDisplayDateComparator());
1137
1138        Date now = new Date();
1139
1140        for (int i = 0; i < articles.size(); i++) {
1141            JournalArticle article = (JournalArticle)articles.get(i);
1142
1143            if (article.getDisplayDate().before(now)) {
1144                return article;
1145            }
1146        }
1147
1148        return (JournalArticle)articles.get(0);
1149    }
1150
1151    public JournalArticle getLatestArticle(long groupId, String articleId)
1152        throws PortalException, SystemException {
1153
1154        return getLatestArticle(groupId, articleId, null);
1155    }
1156
1157    public JournalArticle getLatestArticle(
1158            long groupId, String articleId, Boolean approved)
1159        throws PortalException, SystemException {
1160
1161        List articles = null;
1162
1163        if (approved == null) {
1164            articles = journalArticlePersistence.findByG_A(
1165                groupId, articleId, 0, 1);
1166        }
1167        else {
1168            articles = journalArticlePersistence.findByG_A_A(
1169                groupId, articleId, approved.booleanValue(), 0, 1);
1170        }
1171
1172        if (articles.size() == 0) {
1173            throw new NoSuchArticleException();
1174        }
1175
1176        return (JournalArticle)articles.get(0);
1177    }
1178
1179    public double getLatestVersion(long groupId, String articleId)
1180        throws PortalException, SystemException {
1181
1182        JournalArticle article = getLatestArticle(groupId, articleId);
1183
1184        return article.getVersion();
1185    }
1186
1187    public double getLatestVersion(
1188            long groupId, String articleId, Boolean approved)
1189        throws PortalException, SystemException {
1190
1191        JournalArticle article = getLatestArticle(groupId, articleId, approved);
1192
1193        return article.getVersion();
1194    }
1195
1196    public List getStructureArticles(long groupId, String structureId)
1197        throws SystemException {
1198
1199        return journalArticlePersistence.findByG_S(groupId, structureId);
1200    }
1201
1202    public List getStructureArticles(
1203            long groupId, String structureId, int begin, int end,
1204            OrderByComparator obc)
1205        throws SystemException {
1206
1207        return journalArticlePersistence.findByG_S(
1208            groupId, structureId, begin, end, obc);
1209    }
1210
1211    public int getStructureArticlesCount(long groupId, String structureId)
1212        throws SystemException {
1213
1214        return journalArticlePersistence.countByG_S(groupId, structureId);
1215    }
1216
1217    public List getTemplateArticles(long groupId, String templateId)
1218        throws SystemException {
1219
1220        return journalArticlePersistence.findByG_T(groupId, templateId);
1221    }
1222
1223    public List getTemplateArticles(
1224            long groupId, String templateId, int begin, int end,
1225            OrderByComparator obc)
1226        throws SystemException {
1227
1228        return journalArticlePersistence.findByG_T(
1229            groupId, templateId, begin, end, obc);
1230    }
1231
1232    public int getTemplateArticlesCount(long groupId, String templateId)
1233        throws SystemException {
1234
1235        return journalArticlePersistence.countByG_T(groupId, templateId);
1236    }
1237
1238    public boolean hasArticle(long groupId, String articleId)
1239        throws SystemException {
1240
1241        try {
1242            getArticle(groupId, articleId);
1243
1244            return true;
1245        }
1246        catch (PortalException pe) {
1247            return false;
1248        }
1249    }
1250
1251    public boolean isLatestVersion(
1252            long groupId, String articleId, double version)
1253        throws PortalException, SystemException {
1254
1255        if (getLatestVersion(groupId, articleId) == version) {
1256            return true;
1257        }
1258        else {
1259            return false;
1260        }
1261    }
1262
1263    public boolean isLatestVersion(
1264            long groupId, String articleId, double version, Boolean active)
1265        throws PortalException, SystemException {
1266
1267        if (getLatestVersion(groupId, articleId, active) == version) {
1268            return true;
1269        }
1270        else {
1271            return false;
1272        }
1273    }
1274
1275    public void reIndex(String[] ids) throws SystemException {
1276        if (LuceneUtil.INDEX_READ_ONLY) {
1277            return;
1278        }
1279
1280        long companyId = GetterUtil.getLong(ids[0]);
1281
1282        IndexWriter writer = null;
1283
1284        try {
1285            writer = LuceneUtil.getWriter(companyId);
1286
1287            Iterator itr = journalArticlePersistence.findByCompanyId(
1288                companyId).iterator();
1289
1290            while (itr.hasNext()) {
1291                JournalArticle article = (JournalArticle)itr.next();
1292
1293                if (article.isApproved() && article.isIndexable()) {
1294                    long resourcePrimKey = article.getResourcePrimKey();
1295                    long groupId = article.getGroupId();
1296                    String articleId = article.getArticleId();
1297                    double version = article.getVersion();
1298                    String title = article.getTitle();
1299                    String description = article.getDescription();
1300                    String content = article.getContent();
1301                    String type = article.getType();
1302                    Date displayDate = article.getDisplayDate();
1303
1304                    String[] tagsEntries = tagsEntryLocalService.getEntryNames(
1305                        JournalArticle.class.getName(), resourcePrimKey);
1306
1307                    try {
1308                        org.apache.lucene.document.Document doc =
1309                            Indexer.getAddArticleDocument(
1310                                companyId, groupId, articleId, version, title,
1311                                description, content, type, displayDate,
1312                                tagsEntries);
1313
1314                        writer.addDocument(doc);
1315                    }
1316                    catch (Exception e1) {
1317                        _log.error("Reindexing " + article.getId(), e1);
1318                    }
1319                }
1320            }
1321        }
1322        catch (SystemException se) {
1323            throw se;
1324        }
1325        catch (Exception e2) {
1326            throw new SystemException(e2);
1327        }
1328        finally {
1329            try {
1330                if (writer != null) {
1331                    LuceneUtil.write(companyId);
1332                }
1333            }
1334            catch (Exception e) {
1335                _log.error(e);
1336            }
1337        }
1338    }
1339
1340    public JournalArticle removeArticleLocale(
1341            long groupId, String articleId, double version, String languageId)
1342        throws PortalException, SystemException {
1343
1344        JournalArticle article = journalArticlePersistence.findByG_A_V(
1345            groupId, articleId, version);
1346
1347        String content = article.getContent();
1348
1349        if (article.isTemplateDriven()) {
1350            content = JournalUtil.removeArticleLocale(content, languageId);
1351        }
1352        else {
1353            content = LocalizationUtil.removeLocalization(
1354                content, "static-content", languageId);
1355        }
1356
1357        article.setContent(content);
1358
1359        journalArticlePersistence.update(article);
1360
1361        return article;
1362    }
1363
1364    public Hits search(long companyId, long groupId, String keywords)
1365        throws SystemException {
1366
1367        return search(companyId, groupId, keywords, "displayDate");
1368    }
1369
1370    public Hits search(
1371            long companyId, long groupId, String keywords, String sortField)
1372        throws SystemException {
1373
1374        Searcher searcher = null;
1375
1376        try {
1377            HitsImpl hits = new HitsImpl();
1378
1379            BooleanQuery contextQuery = new BooleanQuery();
1380
1381            LuceneUtil.addRequiredTerm(
1382                contextQuery, LuceneFields.PORTLET_ID, Indexer.PORTLET_ID);
1383
1384            if (groupId > 0) {
1385                LuceneUtil.addRequiredTerm(
1386                    contextQuery, LuceneFields.GROUP_ID, groupId);
1387            }
1388
1389            BooleanQuery searchQuery = new BooleanQuery();
1390
1391            if (Validator.isNotNull(keywords)) {
1392                LuceneUtil.addTerm(searchQuery, LuceneFields.TITLE, keywords);
1393                LuceneUtil.addTerm(searchQuery, LuceneFields.CONTENT, keywords);
1394                LuceneUtil.addTerm(
1395                    searchQuery, LuceneFields.DESCRIPTION, keywords);
1396            }
1397
1398            BooleanQuery fullQuery = new BooleanQuery();
1399
1400            fullQuery.add(contextQuery, BooleanClause.Occur.MUST);
1401
1402            if (searchQuery.clauses().size() > 0) {
1403                fullQuery.add(searchQuery, BooleanClause.Occur.MUST);
1404            }
1405
1406            searcher = LuceneUtil.getSearcher(companyId);
1407
1408            Sort sort = new Sort(new SortField(sortField, true));
1409
1410            try {
1411                hits.recordHits(searcher.search(fullQuery, sort), searcher);
1412            }
1413            catch (RuntimeException re) {
1414
1415                // Trying to sort on a field when there are no results throws a
1416                // RuntimeException that should not be rethrown
1417
1418                String msg = GetterUtil.getString(re.getMessage());
1419
1420                if (!msg.endsWith("does not appear to be indexed")) {
1421                    throw re;
1422                }
1423            }
1424
1425            return hits;
1426        }
1427        catch (Exception e) {
1428            return LuceneUtil.closeSearcher(searcher, keywords, e);
1429        }
1430    }
1431
1432    public List search(
1433            long companyId, long groupId, String keywords, Double version,
1434            String type, String structureId, String templateId,
1435            Date displayDateGT, Date displayDateLT, Boolean approved,
1436            Boolean expired, Date reviewDate, int begin, int end,
1437            OrderByComparator obc)
1438        throws SystemException {
1439
1440        return journalArticleFinder.findByKeywords(
1441            companyId, groupId, keywords, version, type, structureId,
1442            templateId, displayDateGT, displayDateLT, approved, expired,
1443            reviewDate, begin, end, obc);
1444    }
1445
1446    public List search(
1447            long companyId, long groupId, String articleId, Double version,
1448            String title, String description, String content, String type,
1449            String structureId, String templateId, Date displayDateGT,
1450            Date displayDateLT, Boolean approved, Boolean expired,
1451            Date reviewDate, boolean andOperator, int begin, int end,
1452            OrderByComparator obc)
1453        throws SystemException {
1454
1455        return journalArticleFinder.findByC_G_A_V_T_D_C_T_S_T_D_A_E_R(
1456            companyId, groupId, articleId, version, title, description, content,
1457            type, structureId, templateId, displayDateGT, displayDateLT,
1458            approved, expired, reviewDate, andOperator, begin, end, obc);
1459    }
1460
1461    public List search(
1462            long companyId, long groupId, String articleId, Double version,
1463            String title, String description, String content, String type,
1464            String[] structureIds, String[] templateIds, Date displayDateGT,
1465            Date displayDateLT, Boolean approved, Boolean expired,
1466            Date reviewDate, boolean andOperator, int begin, int end,
1467            OrderByComparator obc)
1468        throws SystemException {
1469
1470        return journalArticleFinder.findByC_G_A_V_T_D_C_T_S_T_D_A_E_R(
1471            companyId, groupId, articleId, version, title, description, content,
1472            type, structureIds, templateIds, displayDateGT, displayDateLT,
1473            approved, expired, reviewDate, andOperator, begin, end, obc);
1474    }
1475
1476    public int searchCount(
1477            long companyId, long groupId, String keywords, Double version,
1478            String type, String structureId, String templateId,
1479            Date displayDateGT, Date displayDateLT, Boolean approved,
1480            Boolean expired, Date reviewDate)
1481        throws SystemException {
1482
1483        return journalArticleFinder.countByKeywords(
1484            companyId, groupId, keywords, version, type, structureId,
1485            templateId, displayDateGT, displayDateLT, approved, expired,
1486            reviewDate);
1487    }
1488
1489    public int searchCount(
1490            long companyId, long groupId, String articleId, Double version,
1491            String title, String description, String content, String type,
1492            String structureId, String templateId, Date displayDateGT,
1493            Date displayDateLT, Boolean approved, Boolean expired,
1494            Date reviewDate, boolean andOperator)
1495        throws SystemException {
1496
1497        return journalArticleFinder.countByC_G_A_V_T_D_C_T_S_T_D_A_E_R(
1498            companyId, groupId, articleId, version, title, description, content,
1499            type, structureId, templateId, displayDateGT, displayDateLT,
1500            approved, expired, reviewDate, andOperator);
1501    }
1502
1503    public int searchCount(
1504            long companyId, long groupId, String articleId, Double version,
1505            String title, String description, String content, String type,
1506            String[] structureIds, String[] templateIds, Date displayDateGT,
1507            Date displayDateLT, Boolean approved, Boolean expired,
1508            Date reviewDate, boolean andOperator)
1509        throws SystemException {
1510
1511        return journalArticleFinder.countByC_G_A_V_T_D_C_T_S_T_D_A_E_R(
1512            companyId, groupId, articleId, version, title, description, content,
1513            type, structureIds, templateIds, displayDateGT, displayDateLT,
1514            approved, expired, reviewDate, andOperator);
1515    }
1516
1517    public JournalArticle updateArticle(
1518            long userId, long groupId, String articleId, double version,
1519            boolean incrementVersion, String title, String description,
1520            String content, String type, String structureId, String templateId,
1521            int displayDateMonth, int displayDateDay, int displayDateYear,
1522            int displayDateHour, int displayDateMinute, int expirationDateMonth,
1523            int expirationDateDay, int expirationDateYear,
1524            int expirationDateHour, int expirationDateMinute,
1525            boolean neverExpire, int reviewDateMonth, int reviewDateDay,
1526            int reviewDateYear, int reviewDateHour, int reviewDateMinute,
1527            boolean neverReview, boolean indexable, boolean smallImage,
1528            String smallImageURL, File smallFile, Map images, String articleURL,
1529            PortletPreferences prefs, String[] tagsEntries)
1530        throws PortalException, SystemException {
1531
1532        // Article
1533
1534        User user = userPersistence.findByPrimaryKey(userId);
1535        articleId = articleId.trim().toUpperCase();
1536        Date now = new Date();
1537
1538        Date displayDate = PortalUtil.getDate(
1539            displayDateMonth, displayDateDay, displayDateYear,
1540            displayDateHour, displayDateMinute, user.getTimeZone(),
1541            new ArticleDisplayDateException());
1542
1543        Date expirationDate = null;
1544
1545        if (!neverExpire) {
1546            expirationDate = PortalUtil.getDate(
1547                expirationDateMonth, expirationDateDay, expirationDateYear,
1548                expirationDateHour, expirationDateMinute, user.getTimeZone(),
1549                new ArticleExpirationDateException());
1550        }
1551
1552        Date reviewDate = null;
1553
1554        if (!neverReview) {
1555            reviewDate = PortalUtil.getDate(
1556                reviewDateMonth, reviewDateDay, reviewDateYear, reviewDateHour,
1557                reviewDateMinute, user.getTimeZone(),
1558                new ArticleReviewDateException());
1559        }
1560
1561        byte[] smallBytes = null;
1562
1563        try {
1564            smallBytes = FileUtil.getBytes(smallFile);
1565        }
1566        catch (IOException ioe) {
1567        }
1568
1569        validate(
1570            groupId, title, content, type, structureId, templateId, smallImage,
1571            smallImageURL, smallFile, smallBytes);
1572
1573        JournalArticle oldArticle = journalArticlePersistence.findByG_A_V(
1574            groupId, articleId, version);
1575
1576        JournalArticle article = null;
1577
1578        if (incrementVersion) {
1579            double latestVersion = getLatestVersion(groupId, articleId);
1580
1581            long id = counterLocalService.increment();
1582
1583            article = journalArticlePersistence.create(id);
1584
1585            article.setResourcePrimKey(oldArticle.getResourcePrimKey());
1586            article.setGroupId(oldArticle.getGroupId());
1587            article.setCompanyId(user.getCompanyId());
1588            article.setUserId(user.getUserId());
1589            article.setUserName(user.getFullName());
1590            article.setCreateDate(now);
1591            article.setArticleId(articleId);
1592            article.setVersion(MathUtil.format(latestVersion + 0.1, 1, 1));
1593            article.setSmallImageId(oldArticle.getSmallImageId());
1594        }
1595        else {
1596            article = oldArticle;
1597        }
1598
1599        content = format(
1600            groupId, articleId, article.getVersion(), incrementVersion, content,
1601            structureId, images);
1602
1603        boolean approved = oldArticle.isApproved();
1604
1605        if (incrementVersion) {
1606            approved = false;
1607        }
1608
1609        article.setModifiedDate(now);
1610        article.setTitle(title);
1611        article.setDescription(description);
1612        article.setContent(content);
1613        article.setType(type);
1614        article.setStructureId(structureId);
1615        article.setTemplateId(templateId);
1616        article.setDisplayDate(displayDate);
1617        article.setApproved(approved);
1618
1619        if ((expirationDate == null) || expirationDate.after(now)) {
1620            article.setExpired(false);
1621        }
1622        else {
1623            article.setExpired(true);
1624        }
1625
1626        article.setExpirationDate(expirationDate);
1627        article.setReviewDate(reviewDate);
1628        article.setIndexable(indexable);
1629        article.setSmallImage(smallImage);
1630
1631        if (article.getSmallImageId() == 0) {
1632            article.setSmallImageId(counterLocalService.increment());
1633        }
1634
1635        article.setSmallImageURL(smallImageURL);
1636
1637        journalArticlePersistence.update(article);
1638
1639        // Small image
1640
1641        saveImages(
1642            smallImage, article.getSmallImageId(), smallFile, smallBytes);
1643
1644        // Tags
1645
1646        updateTagsAsset(userId, article, tagsEntries);
1647
1648        // Email
1649
1650        if (incrementVersion) {
1651            sendEmail(article, articleURL, prefs, "requested");
1652        }
1653
1654        // Lucene
1655
1656        try {
1657            if (article.isIndexable()) {
1658                if (article.isApproved()) {
1659                    Indexer.updateArticle(
1660                        article.getCompanyId(), article.getGroupId(),
1661                        article.getArticleId(), article.getVersion(),
1662                        article.getTitle(), article.getDescription(),
1663                        article.getContent(), article.getType(),
1664                        article.getDisplayDate(), tagsEntries);
1665                }
1666                else {
1667                    Indexer.deleteArticle(
1668                        article.getCompanyId(), article.getArticleId());
1669                }
1670            }
1671        }
1672        catch (IOException ioe) {
1673            _log.error("Indexing " + article.getPrimaryKey(), ioe);
1674        }
1675
1676        return article;
1677    }
1678
1679    public JournalArticle updateContent(
1680            long groupId, String articleId, double version, String content)
1681        throws PortalException, SystemException {
1682
1683        JournalArticle article = journalArticlePersistence.findByG_A_V(
1684            groupId, articleId, version);
1685
1686        article.setContent(content);
1687
1688        journalArticlePersistence.update(article);
1689
1690        return article;
1691    }
1692
1693    public void updateTagsAsset(
1694            long userId, JournalArticle article, String[] tagsEntries)
1695        throws PortalException, SystemException {
1696
1697        boolean updateAsset = true;
1698
1699        if (article.getVersion() == 1) {
1700        }
1701        else if (!article.isApproved()) {
1702            updateAsset = false;
1703        }
1704        else if (!isLatestVersion(
1705                    article.getGroupId(), article.getArticleId(),
1706                    article.getVersion(), Boolean.TRUE)) {
1707
1708                updateAsset = false;
1709        }
1710
1711        if (updateAsset) {
1712            tagsAssetLocalService.updateAsset(
1713                userId, article.getGroupId(), JournalArticle.class.getName(),
1714                article.getResourcePrimKey(), tagsEntries, null, null,
1715                article.getDisplayDate(), article.getExpirationDate(),
1716                ContentTypes.TEXT_HTML, article.getTitle(),
1717                article.getDescription(), null, null, 0, 0, null, false);
1718        }
1719    }
1720
1721    protected void checkStructure(JournalArticle article)
1722        throws DocumentException, PortalException, SystemException {
1723
1724        JournalStructure structure = journalStructurePersistence.findByG_S(
1725            article.getGroupId(), article.getStructureId());
1726
1727        String content = GetterUtil.getString(article.getContent());
1728
1729        SAXReader reader = new SAXReader();
1730
1731        Document contentDoc = reader.read(new StringReader(content));
1732        Document xsdDoc = reader.read(new StringReader(structure.getXsd()));
1733
1734        try {
1735            checkStructure(contentDoc, xsdDoc.getRootElement());
1736        }
1737        catch (StructureXsdException sxsde) {
1738            long groupId = article.getGroupId();
1739            String articleId = article.getArticleId();
1740            double version = article.getVersion();
1741
1742            _log.error(
1743                "Article {groupId=" + groupId + ", articleId=" + articleId +
1744                    ", version=" + version +
1745                        "} has content that does not match its structure: " +
1746                            sxsde.getMessage());
1747        }
1748    }
1749
1750    protected void checkStructure(Document contentDoc, Element root)
1751        throws PortalException {
1752
1753        Iterator itr = root.elements().iterator();
1754
1755        while (itr.hasNext()) {
1756            Element el = (Element)itr.next();
1757
1758            checkStructureField(el, contentDoc);
1759
1760            checkStructure(contentDoc, el);
1761        }
1762    }
1763
1764    protected void checkStructureField(Element el, Document contentDoc)
1765        throws PortalException {
1766
1767        StringMaker elPath = new StringMaker();
1768
1769        elPath.append(el.attributeValue("name"));
1770
1771        Element elParent = (Element)el.getParent();
1772
1773        for (;;) {
1774            if ((elParent == null) ||
1775                (elParent.getName().equals("root"))) {
1776
1777                break;
1778            }
1779
1780            elPath.insert(
1781                0, elParent.attributeValue("name") + StringPool.COMMA);
1782
1783            elParent = (Element)elParent.getParent();
1784        }
1785
1786        String[] elPathNames = StringUtil.split(elPath.toString());
1787
1788        Element contentEl = contentDoc.getRootElement();
1789
1790        for (int i = 0; i < elPathNames.length; i++) {
1791            boolean foundEl = false;
1792
1793            Iterator itr = contentEl.elements().iterator();
1794
1795            while (itr.hasNext()) {
1796                Element tempEl = (Element)itr.next();
1797
1798                if (elPathNames[i].equals(
1799                        tempEl.attributeValue("name", StringPool.BLANK))) {
1800
1801                    contentEl = tempEl;
1802                    foundEl = true;
1803
1804                    break;
1805                }
1806            }
1807
1808            if (!foundEl) {
1809                String elType = contentEl.attributeValue(
1810                    "type", StringPool.BLANK);
1811
1812                if (!elType.equals("list") && !elType.equals("multi-list")) {
1813                    throw new StructureXsdException(elPath.toString());
1814                }
1815
1816                break;
1817            }
1818        }
1819    }
1820
1821    protected String format(
1822            long groupId, String articleId, double version,
1823            boolean incrementVersion, String content, String structureId,
1824            Map images)
1825        throws SystemException {
1826
1827        if (Validator.isNotNull(structureId)) {
1828            SAXReader reader = new SAXReader();
1829
1830            Document doc = null;
1831
1832            try {
1833                doc = reader.read(new StringReader(content));
1834
1835                Element root = doc.getRootElement();
1836
1837                format(
1838                    groupId, articleId, version, incrementVersion,
1839                    root, images);
1840
1841                content = JournalUtil.formatXML(doc);
1842            }
1843            catch (DocumentException de) {
1844                _log.error(de);
1845            }
1846            catch (IOException ioe) {
1847                _log.error(ioe);
1848            }
1849        }
1850
1851        content = Html.replaceMsWordCharacters(content);
1852
1853        return content;
1854    }
1855
1856    protected void format(
1857            long groupId, String articleId, double version,
1858            boolean incrementVersion, Element root, Map images)
1859        throws SystemException {
1860
1861        Iterator itr = root.elements().iterator();
1862
1863        while (itr.hasNext()) {
1864            Element el = (Element)itr.next();
1865
1866            String elName = el.attributeValue("name", StringPool.BLANK);
1867            String elType = el.attributeValue("type", StringPool.BLANK);
1868
1869            if (elType.equals("image")) {
1870                formatImage(
1871                    groupId, articleId, version, incrementVersion, el, elName,
1872                    images);
1873            }
1874            /*else if (elType.equals("text_area")) {
1875                Element dynamicContent = el.element("dynamic-content");
1876
1877                String text = dynamicContent.getText();
1878
1879                // LEP-1594
1880
1881                try {
1882                    text = ParserUtils.trimTags(
1883                        text, new String[] {"script"}, false, true);
1884                }
1885                catch (ParserException pe) {
1886                    text = pe.getLocalizedMessage();
1887                }
1888                catch (UnsupportedEncodingException uee) {
1889                    text = uee.getLocalizedMessage();
1890                }
1891
1892                dynamicContent.setText(text);
1893            }*/
1894
1895            format(
1896                groupId, articleId, version, incrementVersion, el, images);
1897        }
1898    }
1899
1900    protected void formatImage(
1901            long groupId, String articleId, double version,
1902            boolean incrementVersion, Element el, String elName, Map images)
1903        throws SystemException {
1904
1905        List imageContents = el.elements("dynamic-content");
1906
1907        Iterator itr = imageContents.listIterator();
1908
1909        while (itr.hasNext()) {
1910            Element dynamicContent = (Element)itr.next();
1911
1912            String elLanguage = dynamicContent.attributeValue(
1913                "language-id", StringPool.BLANK);
1914
1915            if (!elLanguage.equals(StringPool.BLANK)) {
1916                elLanguage = "_" + elLanguage;
1917            }
1918
1919            long imageId =
1920                journalArticleImageLocalService.getArticleImageId(
1921                    groupId, articleId, version, elName, elLanguage);
1922
1923            double oldVersion = MathUtil.format(version - 0.1, 1, 1);
1924
1925            long oldImageId = 0;
1926
1927            if (oldVersion >= 1) {
1928                oldImageId =
1929                    journalArticleImageLocalService.getArticleImageId(
1930                        groupId, articleId, oldVersion, elName, elLanguage);
1931            }
1932
1933            String elContent =
1934                "/image/journal/article?img_id=" + imageId + "&t=" +
1935                    ImageServletTokenUtil.getToken(imageId);
1936
1937            if (dynamicContent.getText().equals("delete")) {
1938                dynamicContent.setText(StringPool.BLANK);
1939
1940                ImageLocalUtil.deleteImage(imageId);
1941
1942                String defaultElLanguage = "";
1943
1944                if (!Validator.isNotNull(elLanguage)) {
1945                    defaultElLanguage =
1946                        "_" + LocaleUtil.toLanguageId(LocaleUtil.getDefault());
1947                }
1948
1949                long defaultImageId =
1950                    journalArticleImageLocalService.getArticleImageId(
1951                        groupId, articleId, version, elName, defaultElLanguage);
1952
1953                ImageLocalUtil.deleteImage(defaultImageId);
1954
1955                continue;
1956            }
1957
1958            byte[] bytes = (byte[])images.get(elName + elLanguage);
1959
1960            if (bytes != null && (bytes.length > 0)) {
1961                dynamicContent.setText(elContent);
1962                dynamicContent.addAttribute("id", String.valueOf(imageId));
1963
1964                ImageLocalUtil.updateImage(imageId, bytes);
1965
1966                continue;
1967            }
1968
1969            if ((version > JournalArticleImpl.DEFAULT_VERSION) &&
1970                (incrementVersion)) {
1971
1972                Image oldImage = null;
1973
1974                if (oldImageId > 0) {
1975                    oldImage = ImageLocalUtil.getImage(oldImageId);
1976                }
1977
1978                if (oldImage != null) {
1979                    dynamicContent.setText(elContent);
1980                    dynamicContent.addAttribute("id", String.valueOf(imageId));
1981
1982                    bytes = oldImage.getTextObj();
1983
1984                    ImageLocalUtil.updateImage(imageId, bytes);
1985                }
1986
1987                continue;
1988            }
1989
1990            Image image = ImageLocalUtil.getImage(imageId);
1991
1992            if (image != null) {
1993                dynamicContent.setText(elContent);
1994                dynamicContent.addAttribute("id", String.valueOf(imageId));
1995
1996                continue;
1997            }
1998
1999            String defaultElLanguage = "";
2000
2001            if (!Validator.isNotNull(elLanguage)) {
2002                defaultElLanguage =
2003                    "_" + LocaleUtil.toLanguageId(LocaleUtil.getDefault());
2004            }
2005
2006            long defaultImageId =
2007                journalArticleImageLocalService.getArticleImageId(
2008                    groupId, articleId, version, elName, defaultElLanguage);
2009
2010            Image defaultImage = ImageLocalUtil.getImage(defaultImageId);
2011
2012            if (defaultImage != null) {
2013                dynamicContent.setText(elContent);
2014                dynamicContent.addAttribute("id", String.valueOf(imageId));
2015
2016                bytes = defaultImage.getTextObj();
2017
2018                ImageLocalUtil.updateImage(imageId, bytes);
2019
2020                continue;
2021            }
2022
2023            dynamicContent.setText(StringPool.BLANK);
2024        }
2025    }
2026
2027    protected void saveImages(
2028            boolean smallImage, long smallImageId, File smallFile,
2029            byte[] smallBytes)
2030        throws SystemException {
2031
2032        if (smallImage) {
2033            if ((smallFile != null) && (smallBytes != null)) {
2034                ImageLocalUtil.updateImage(smallImageId, smallBytes);
2035            }
2036        }
2037        else {
2038            ImageLocalUtil.deleteImage(smallImageId);
2039        }
2040    }
2041
2042    protected void sendEmail(
2043            JournalArticle article, String articleURL, PortletPreferences prefs,
2044            String emailType)
2045        throws PortalException, SystemException {
2046
2047        try {
2048            if (prefs == null) {
2049                return;
2050            }
2051            else if (emailType.equals("denied") &&
2052                JournalUtil.getEmailArticleApprovalDeniedEnabled(prefs)) {
2053            }
2054            else if (emailType.equals("granted") &&
2055                     JournalUtil.getEmailArticleApprovalGrantedEnabled(prefs)) {
2056            }
2057            else if (emailType.equals("requested") &&
2058                     JournalUtil.getEmailArticleApprovalRequestedEnabled(
2059                        prefs)) {
2060            }
2061            else if (emailType.equals("review") &&
2062                     JournalUtil.getEmailArticleReviewEnabled(prefs)) {
2063            }
2064            else {
2065                return;
2066            }
2067
2068            Company company = companyPersistence.findByPrimaryKey(
2069                article.getCompanyId());
2070
2071            User user = userPersistence.findByPrimaryKey(article.getUserId());
2072
2073            articleURL +=
2074                "&groupId=" + article.getGroupId() + "&articleId=" +
2075                    article.getArticleId() + "&version=" + article.getVersion();
2076
2077            String portletName = PortalUtil.getPortletTitle(
2078                PortletKeys.JOURNAL, user);
2079
2080            String fromName = JournalUtil.getEmailFromName(prefs);
2081            String fromAddress = JournalUtil.getEmailFromAddress(prefs);
2082
2083            String toName = user.getFullName();
2084            String toAddress = user.getEmailAddress();
2085
2086            if (emailType.equals("requested") ||
2087                emailType.equals("review")) {
2088
2089                String tempToName = fromName;
2090                String tempToAddress = fromAddress;
2091
2092                fromName = toName;
2093                fromAddress = toAddress;
2094
2095                toName = tempToName;
2096                toAddress = tempToAddress;
2097            }
2098
2099            String subject = null;
2100            String body = null;
2101
2102            if (emailType.equals("denied")) {
2103                subject =
2104                    JournalUtil.getEmailArticleApprovalDeniedSubject(prefs);
2105                body = JournalUtil.getEmailArticleApprovalDeniedBody(prefs);
2106            }
2107            else if (emailType.equals("granted")) {
2108                subject =
2109                    JournalUtil.getEmailArticleApprovalGrantedSubject(prefs);
2110                body = JournalUtil.getEmailArticleApprovalGrantedBody(prefs);
2111            }
2112            else if (emailType.equals("requested")) {
2113                subject =
2114                    JournalUtil.getEmailArticleApprovalRequestedSubject(prefs);
2115                body = JournalUtil.getEmailArticleApprovalRequestedBody(prefs);
2116            }
2117            else if (emailType.equals("review")) {
2118                subject = JournalUtil.getEmailArticleReviewSubject(prefs);
2119                body = JournalUtil.getEmailArticleReviewBody(prefs);
2120            }
2121
2122            subject = StringUtil.replace(
2123                subject,
2124                new String[] {
2125                    "[$ARTICLE_ID$]",
2126                    "[$ARTICLE_TITLE$]",
2127                    "[$ARTICLE_URL$]",
2128                    "[$ARTICLE_VERSION$]",
2129                    "[$FROM_ADDRESS$]",
2130                    "[$FROM_NAME$]",
2131                    "[$PORTAL_URL$]",
2132                    "[$PORTLET_NAME$]",
2133                    "[$TO_ADDRESS$]",
2134                    "[$TO_NAME$]"
2135                },
2136                new String[] {
2137                    article.getArticleId(),
2138                    article.getTitle(),
2139                    articleURL,
2140                    String.valueOf(article.getVersion()),
2141                    fromAddress,
2142                    fromName,
2143                    company.getVirtualHost(),
2144                    portletName,
2145                    toAddress,
2146                    toName,
2147                });
2148
2149            body = StringUtil.replace(
2150                body,
2151                new String[] {
2152                    "[$ARTICLE_ID$]",
2153                    "[$ARTICLE_TITLE$]",
2154                    "[$ARTICLE_URL$]",
2155                    "[$ARTICLE_VERSION$]",
2156                    "[$FROM_ADDRESS$]",
2157                    "[$FROM_NAME$]",
2158                    "[$PORTAL_URL$]",
2159                    "[$PORTLET_NAME$]",
2160                    "[$TO_ADDRESS$]",
2161                    "[$TO_NAME$]"
2162                },
2163                new String[] {
2164                    article.getArticleId(),
2165                    article.getTitle(),
2166                    articleURL,
2167                    String.valueOf(article.getVersion()),
2168                    fromAddress,
2169                    fromName,
2170                    company.getVirtualHost(),
2171                    portletName,
2172                    toAddress,
2173                    toName,
2174                });
2175
2176            InternetAddress from = new InternetAddress(fromAddress, fromName);
2177
2178            InternetAddress to = new InternetAddress(toAddress, toName);
2179
2180            MailMessage message = new MailMessage(
2181                from, to, subject, body, true);
2182
2183            mailService.sendEmail(message);
2184        }
2185        catch (IOException ioe) {
2186            throw new SystemException(ioe);
2187        }
2188        catch (PortalException pe) {
2189            throw pe;
2190        }
2191    }
2192
2193    protected void validate(
2194            long groupId, String articleId, boolean autoArticleId, String title,
2195            String content, String type, String structureId, String templateId,
2196            boolean smallImage, String smallImageURL, File smallFile,
2197            byte[] smallBytes)
2198        throws PortalException, SystemException {
2199
2200        if (!autoArticleId) {
2201            if ((Validator.isNull(articleId)) ||
2202                (Validator.isNumber(articleId)) ||
2203                (articleId.indexOf(StringPool.SPACE) != -1)) {
2204
2205                throw new ArticleIdException();
2206            }
2207
2208            try {
2209                journalArticlePersistence.findByG_A_V(
2210                    groupId, articleId, JournalArticleImpl.DEFAULT_VERSION);
2211
2212                throw new DuplicateArticleIdException();
2213            }
2214            catch (NoSuchArticleException nste) {
2215            }
2216        }
2217
2218        validate(
2219            groupId, title, content, type, structureId, templateId,
2220            smallImage, smallImageURL, smallFile, smallBytes);
2221    }
2222
2223    protected void validate(
2224            long groupId, String title, String content, String type,
2225            String structureId, String templateId, boolean smallImage,
2226            String smallImageURL, File smallFile, byte[] smallBytes)
2227        throws PortalException, SystemException {
2228
2229        if (Validator.isNull(title)) {
2230            throw new ArticleTitleException();
2231        }
2232        else if (Validator.isNull(content)) {
2233            throw new ArticleContentException();
2234        }
2235        else if (Validator.isNull(type)) {
2236            throw new ArticleTypeException();
2237        }
2238
2239        if (Validator.isNotNull(structureId)) {
2240            journalStructurePersistence.findByG_S(groupId, structureId);
2241
2242            JournalTemplate template = journalTemplatePersistence.findByG_T(
2243                groupId, templateId);
2244
2245            if (!template.getStructureId().equals(structureId)) {
2246                throw new NoSuchTemplateException();
2247            }
2248        }
2249
2250        String[] imageExtensions =
2251            PropsUtil.getArray(PropsUtil.JOURNAL_IMAGE_EXTENSIONS);
2252
2253        if (smallImage && Validator.isNull(smallImageURL) &&
2254            smallFile != null && smallBytes != null) {
2255
2256            String smallImageName = smallFile.getName();
2257
2258            if (smallImageName != null) {
2259                boolean validSmallImageExtension = false;
2260
2261                for (int i = 0; i < imageExtensions.length; i++) {
2262                    if (StringPool.STAR.equals(imageExtensions[i]) ||
2263                        StringUtil.endsWith(
2264                            smallImageName, imageExtensions[i])) {
2265
2266                        validSmallImageExtension = true;
2267
2268                        break;
2269                    }
2270                }
2271
2272                if (!validSmallImageExtension) {
2273                    throw new ArticleSmallImageNameException(smallImageName);
2274                }
2275            }
2276
2277            long smallImageMaxSize = GetterUtil.getLong(
2278                PropsUtil.get(PropsUtil.JOURNAL_IMAGE_SMALL_MAX_SIZE));
2279
2280            if ((smallImageMaxSize > 0) &&
2281                ((smallBytes == null) ||
2282                    (smallBytes.length > smallImageMaxSize))) {
2283
2284                throw new ArticleSmallImageSizeException();
2285            }
2286        }
2287    }
2288
2289    private static final String _TOKEN_PAGE_BREAK = PropsUtil.get(
2290        PropsUtil.JOURNAL_ARTICLE_TOKEN_PAGE_BREAK);
2291
2292    private static Log _log =
2293        LogFactory.getLog(JournalArticleLocalServiceImpl.class);
2294
2295}