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