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