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