001    /**
002     * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portlet.journal.service.impl;
016    
017    import com.liferay.portal.NoSuchImageException;
018    import com.liferay.portal.NoSuchUserException;
019    import com.liferay.portal.kernel.dao.orm.QueryUtil;
020    import com.liferay.portal.kernel.exception.PortalException;
021    import com.liferay.portal.kernel.exception.SystemException;
022    import com.liferay.portal.kernel.log.Log;
023    import com.liferay.portal.kernel.log.LogFactoryUtil;
024    import com.liferay.portal.kernel.mail.MailMessage;
025    import com.liferay.portal.kernel.messaging.DestinationNames;
026    import com.liferay.portal.kernel.messaging.Message;
027    import com.liferay.portal.kernel.messaging.MessageBusUtil;
028    import com.liferay.portal.kernel.search.Indexer;
029    import com.liferay.portal.kernel.search.IndexerRegistryUtil;
030    import com.liferay.portal.kernel.servlet.ImageServletTokenUtil;
031    import com.liferay.portal.kernel.util.CalendarFactoryUtil;
032    import com.liferay.portal.kernel.util.ContentTypes;
033    import com.liferay.portal.kernel.util.FileUtil;
034    import com.liferay.portal.kernel.util.GetterUtil;
035    import com.liferay.portal.kernel.util.HtmlUtil;
036    import com.liferay.portal.kernel.util.HttpUtil;
037    import com.liferay.portal.kernel.util.LocaleUtil;
038    import com.liferay.portal.kernel.util.LocalizationUtil;
039    import com.liferay.portal.kernel.util.MathUtil;
040    import com.liferay.portal.kernel.util.OrderByComparator;
041    import com.liferay.portal.kernel.util.PropsKeys;
042    import com.liferay.portal.kernel.util.StringPool;
043    import com.liferay.portal.kernel.util.StringUtil;
044    import com.liferay.portal.kernel.util.Time;
045    import com.liferay.portal.kernel.util.Validator;
046    import com.liferay.portal.kernel.workflow.WorkflowConstants;
047    import com.liferay.portal.kernel.workflow.WorkflowHandlerRegistryUtil;
048    import com.liferay.portal.kernel.xml.Document;
049    import com.liferay.portal.kernel.xml.DocumentException;
050    import com.liferay.portal.kernel.xml.Element;
051    import com.liferay.portal.kernel.xml.Node;
052    import com.liferay.portal.kernel.xml.SAXReaderUtil;
053    import com.liferay.portal.kernel.xml.XPath;
054    import com.liferay.portal.model.Company;
055    import com.liferay.portal.model.Image;
056    import com.liferay.portal.model.PortletPreferencesIds;
057    import com.liferay.portal.model.ResourceConstants;
058    import com.liferay.portal.model.User;
059    import com.liferay.portal.service.ServiceContext;
060    import com.liferay.portal.service.ServiceContextUtil;
061    import com.liferay.portal.servlet.filters.cache.CacheUtil;
062    import com.liferay.portal.theme.ThemeDisplay;
063    import com.liferay.portal.util.PortalUtil;
064    import com.liferay.portal.util.PortletKeys;
065    import com.liferay.portal.util.PrefsPropsUtil;
066    import com.liferay.portal.util.PropsUtil;
067    import com.liferay.portal.util.PropsValues;
068    import com.liferay.portlet.asset.NoSuchEntryException;
069    import com.liferay.portlet.asset.model.AssetEntry;
070    import com.liferay.portlet.expando.model.ExpandoBridge;
071    import com.liferay.portlet.journal.ArticleContentException;
072    import com.liferay.portlet.journal.ArticleDisplayDateException;
073    import com.liferay.portlet.journal.ArticleExpirationDateException;
074    import com.liferay.portlet.journal.ArticleIdException;
075    import com.liferay.portlet.journal.ArticleReviewDateException;
076    import com.liferay.portlet.journal.ArticleSmallImageNameException;
077    import com.liferay.portlet.journal.ArticleSmallImageSizeException;
078    import com.liferay.portlet.journal.ArticleTitleException;
079    import com.liferay.portlet.journal.ArticleTypeException;
080    import com.liferay.portlet.journal.ArticleVersionException;
081    import com.liferay.portlet.journal.DuplicateArticleIdException;
082    import com.liferay.portlet.journal.NoSuchArticleException;
083    import com.liferay.portlet.journal.NoSuchArticleResourceException;
084    import com.liferay.portlet.journal.NoSuchTemplateException;
085    import com.liferay.portlet.journal.StructureXsdException;
086    import com.liferay.portlet.journal.model.JournalArticle;
087    import com.liferay.portlet.journal.model.JournalArticleConstants;
088    import com.liferay.portlet.journal.model.JournalArticleDisplay;
089    import com.liferay.portlet.journal.model.JournalStructure;
090    import com.liferay.portlet.journal.model.JournalTemplate;
091    import com.liferay.portlet.journal.model.impl.JournalArticleDisplayImpl;
092    import com.liferay.portlet.journal.service.base.JournalArticleLocalServiceBaseImpl;
093    import com.liferay.portlet.journal.util.JournalUtil;
094    import com.liferay.portlet.journal.util.comparator.ArticleIDComparator;
095    import com.liferay.portlet.journal.util.comparator.ArticleVersionComparator;
096    import com.liferay.portlet.journalcontent.util.JournalContentUtil;
097    
098    import java.io.File;
099    import java.io.IOException;
100    
101    import java.util.Calendar;
102    import java.util.Date;
103    import java.util.HashSet;
104    import java.util.List;
105    import java.util.Map;
106    import java.util.Set;
107    
108    import javax.mail.internet.InternetAddress;
109    
110    import javax.portlet.PortletPreferences;
111    
112    /**
113     * @author Brian Wing Shun Chan
114     * @author Raymond Augé
115     * @author Bruno Farache
116     */
117    public class JournalArticleLocalServiceImpl
118            extends JournalArticleLocalServiceBaseImpl {
119    
120            public JournalArticle addArticle(
121                            long userId, long groupId, String articleId, boolean autoArticleId,
122                            double version, String title, String description, String content,
123                            String type, String structureId, String templateId,
124                            int displayDateMonth, int displayDateDay, int displayDateYear,
125                            int displayDateHour, int displayDateMinute, int expirationDateMonth,
126                            int expirationDateDay, int expirationDateYear,
127                            int expirationDateHour, int expirationDateMinute,
128                            boolean neverExpire, int reviewDateMonth, int reviewDateDay,
129                            int reviewDateYear, int reviewDateHour, int reviewDateMinute,
130                            boolean neverReview, boolean indexable, boolean smallImage,
131                            String smallImageURL, File smallFile, Map<String, byte[]> images,
132                            String articleURL, ServiceContext serviceContext)
133                    throws PortalException, SystemException {
134    
135                    // Article
136    
137                    User user = userPersistence.findByPrimaryKey(userId);
138                    articleId = articleId.trim().toUpperCase();
139    
140                    Date displayDate = PortalUtil.getDate(
141                            displayDateMonth, displayDateDay, displayDateYear,
142                            displayDateHour, displayDateMinute, user.getTimeZone(),
143                            new ArticleDisplayDateException());
144    
145                    Date expirationDate = null;
146    
147                    if (!neverExpire) {
148                            expirationDate = PortalUtil.getDate(
149                                    expirationDateMonth, expirationDateDay, expirationDateYear,
150                                    expirationDateHour, expirationDateMinute, user.getTimeZone(),
151                                    new ArticleExpirationDateException());
152                    }
153    
154                    Date reviewDate = null;
155    
156                    if (!neverReview) {
157                            reviewDate = PortalUtil.getDate(
158                                    reviewDateMonth, reviewDateDay, reviewDateYear, reviewDateHour,
159                                    reviewDateMinute, user.getTimeZone(),
160                                    new ArticleReviewDateException());
161                    }
162    
163                    byte[] smallBytes = null;
164    
165                    try {
166                            smallBytes = FileUtil.getBytes(smallFile);
167                    }
168                    catch (IOException ioe) {
169                    }
170    
171                    Date now = new Date();
172    
173                    validate(
174                            groupId, articleId, autoArticleId, version, title, content, type,
175                            structureId, templateId, smallImage, smallImageURL, smallFile,
176                            smallBytes);
177    
178                    if (autoArticleId) {
179                            articleId = String.valueOf(counterLocalService.increment());
180                    }
181    
182                    long id = counterLocalService.increment();
183    
184                    long resourcePrimKey =
185                            journalArticleResourceLocalService.getArticleResourcePrimKey(
186                                    groupId, articleId);
187    
188                    JournalArticle article = journalArticlePersistence.create(id);
189    
190                    content = format(
191                            groupId, articleId, version, false, content, structureId, images);
192    
193                    article.setUuid(serviceContext.getUuid());
194                    article.setResourcePrimKey(resourcePrimKey);
195                    article.setGroupId(groupId);
196                    article.setCompanyId(user.getCompanyId());
197                    article.setUserId(user.getUserId());
198                    article.setUserName(user.getFullName());
199                    article.setCreateDate(serviceContext.getCreateDate(now));
200                    article.setModifiedDate(serviceContext.getModifiedDate(now));
201                    article.setArticleId(articleId);
202                    article.setVersion(version);
203                    article.setTitle(title);
204                    article.setUrlTitle(getUniqueUrlTitle(id, groupId, articleId, title));
205                    article.setDescription(description);
206                    article.setContent(content);
207                    article.setType(type);
208                    article.setStructureId(structureId);
209                    article.setTemplateId(templateId);
210                    article.setDisplayDate(displayDate);
211    
212                    if ((expirationDate == null) || expirationDate.after(now)) {
213                            article.setStatus(WorkflowConstants.STATUS_DRAFT);
214                    }
215                    else {
216                            article.setStatus(WorkflowConstants.STATUS_EXPIRED);
217                    }
218    
219                    article.setExpirationDate(expirationDate);
220                    article.setReviewDate(reviewDate);
221                    article.setIndexable(indexable);
222                    article.setSmallImage(smallImage);
223                    article.setSmallImageId(counterLocalService.increment());
224                    article.setSmallImageURL(smallImageURL);
225    
226                    journalArticlePersistence.update(article, false);
227    
228                    // Resources
229    
230                    if (serviceContext.getAddCommunityPermissions() ||
231                            serviceContext.getAddGuestPermissions()) {
232    
233                            addArticleResources(
234                                    article, serviceContext.getAddCommunityPermissions(),
235                                    serviceContext.getAddGuestPermissions());
236                    }
237                    else {
238                            addArticleResources(
239                                    article, serviceContext.getCommunityPermissions(),
240                                    serviceContext.getGuestPermissions());
241                    }
242    
243                    // Expando
244    
245                    ExpandoBridge expandoBridge = article.getExpandoBridge();
246    
247                    expandoBridge.setAttributes(serviceContext);
248    
249                    // Small image
250    
251                    saveImages(
252                            smallImage, article.getSmallImageId(), smallFile, smallBytes);
253    
254                    // Asset
255    
256                    updateAsset(
257                            userId, article, serviceContext.getAssetCategoryIds(),
258                            serviceContext.getAssetTagNames());
259    
260                    // Message boards
261    
262                    if (PropsValues.JOURNAL_ARTICLE_COMMENTS_ENABLED) {
263                            mbMessageLocalService.addDiscussionMessage(
264                                    userId, article.getUserName(), groupId,
265                                    JournalArticle.class.getName(), resourcePrimKey,
266                                    WorkflowConstants.ACTION_PUBLISH);
267                    }
268    
269                    // Email
270    
271                    PortletPreferences preferences =
272                            ServiceContextUtil.getPortletPreferences(serviceContext);
273    
274                    try {
275                            sendEmail(article, articleURL, preferences, "requested");
276                    }
277                    catch (IOException ioe) {
278                            throw new SystemException(ioe);
279                    }
280    
281                    // Workflow
282    
283                    WorkflowHandlerRegistryUtil.startWorkflowInstance(
284                            user.getCompanyId(), groupId, userId,
285                            JournalArticle.class.getName(), article.getResourcePrimKey(),
286                            article, serviceContext);
287    
288                    return article;
289            }
290    
291            public void addArticleResources(
292                            JournalArticle article, boolean addCommunityPermissions,
293                            boolean addGuestPermissions)
294                    throws PortalException, SystemException {
295    
296                    resourceLocalService.addResources(
297                            article.getCompanyId(), article.getGroupId(),
298                            article.getUserId(), JournalArticle.class.getName(),
299                            article.getResourcePrimKey(), false, addCommunityPermissions,
300                            addGuestPermissions);
301            }
302    
303            public void addArticleResources(
304                            JournalArticle article, String[] communityPermissions,
305                            String[] guestPermissions)
306                    throws PortalException, SystemException {
307    
308                    resourceLocalService.addModelResources(
309                            article.getCompanyId(), article.getGroupId(),
310                            article.getUserId(), JournalArticle.class.getName(),
311                            article.getResourcePrimKey(), communityPermissions,
312                            guestPermissions);
313            }
314    
315            public void addArticleResources(
316                            long groupId, String articleId, boolean addCommunityPermissions,
317                            boolean addGuestPermissions)
318                    throws PortalException, SystemException {
319    
320                    JournalArticle article = getLatestArticle(groupId, articleId);
321    
322                    addArticleResources(
323                            article, addCommunityPermissions, addGuestPermissions);
324            }
325    
326            public void addArticleResources(
327                            long groupId, String articleId, String[] communityPermissions,
328                            String[] guestPermissions)
329                    throws PortalException, SystemException {
330    
331                    JournalArticle article = getLatestArticle(groupId, articleId);
332    
333                    addArticleResources(article, communityPermissions, guestPermissions);
334            }
335    
336            public JournalArticle checkArticleResourcePrimKey(
337                            long groupId, String articleId, double version)
338                    throws PortalException, SystemException {
339    
340                    JournalArticle article = journalArticlePersistence.findByG_A_V(
341                            groupId, articleId, version);
342    
343                    if (article.getResourcePrimKey() > 0) {
344                            return article;
345                    }
346    
347                    long resourcePrimKey =
348                            journalArticleResourceLocalService.getArticleResourcePrimKey(
349                                    groupId, articleId);
350    
351                    article.setResourcePrimKey(resourcePrimKey);
352    
353                    journalArticlePersistence.update(article, false);
354    
355                    return article;
356            }
357    
358            public void checkArticles() throws PortalException, SystemException {
359                    Date now = new Date();
360    
361                    List<JournalArticle> articles =
362                            journalArticleFinder.findByExpirationDate(
363                                    WorkflowConstants.STATUS_APPROVED, now,
364                                    new Date(now.getTime() - _journalArticleCheckInterval));
365    
366                    if (_log.isDebugEnabled()) {
367                            _log.debug("Expiring " + articles.size() + " articles");
368                    }
369    
370                    Set<Long> companyIds = new HashSet<Long>();
371    
372                    for (JournalArticle article : articles) {
373                            article.setStatus(WorkflowConstants.STATUS_EXPIRED);
374    
375                            journalArticlePersistence.update(article, false);
376    
377                            if (article.isIndexable()) {
378                                    Indexer indexer = IndexerRegistryUtil.getIndexer(
379                                            JournalArticle.class);
380    
381                                    indexer.delete(article);
382                            }
383    
384                            JournalContentUtil.clearCache(
385                                    article.getGroupId(), article.getArticleId(),
386                                    article.getTemplateId());
387    
388                            companyIds.add(article.getCompanyId());
389                    }
390    
391                    for (long companyId : companyIds) {
392                            CacheUtil.clearCache(companyId);
393                    }
394    
395                    articles = journalArticleFinder.findByReviewDate(
396                            now, new Date(now.getTime() - _journalArticleCheckInterval));
397    
398                    if (_log.isDebugEnabled()) {
399                            _log.debug(
400                                    "Sending review notifications for " + articles.size() +
401                                            " articles");
402                    }
403    
404                    for (JournalArticle article : articles) {
405                            String articleURL = StringPool.BLANK;
406    
407                            long ownerId = article.getGroupId();
408                            int ownerType = PortletKeys.PREFS_OWNER_TYPE_GROUP;
409                            long plid = PortletKeys.PREFS_PLID_SHARED;
410                            String portletId = PortletKeys.JOURNAL;
411    
412                            PortletPreferences preferences =
413                                    portletPreferencesLocalService.getPreferences(
414                                            article.getCompanyId(), ownerId, ownerType, plid,
415                                            portletId);
416    
417                            try {
418                                    sendEmail(article, articleURL, preferences, "review");
419                            }
420                            catch (IOException ioe) {
421                                    throw new SystemException(ioe);
422                            }
423                    }
424            }
425    
426            public void checkNewLine(long groupId, String articleId, double version)
427                    throws PortalException, SystemException {
428    
429                    JournalArticle article = journalArticlePersistence.findByG_A_V(
430                            groupId, articleId, version);
431    
432                    String content = GetterUtil.getString(article.getContent());
433    
434                    if (content.indexOf("\\n") != -1) {
435                            content = StringUtil.replace(
436                                    content,
437                                    new String[] {"\\n", "\\r"},
438                                    new String[] {"\n", "\r"});
439    
440                            article.setContent(content);
441    
442                            journalArticlePersistence.update(article, false);
443                    }
444            }
445    
446            public void checkStructure(long groupId, String articleId, double version)
447                    throws PortalException, SystemException {
448    
449                    JournalArticle article = journalArticlePersistence.findByG_A_V(
450                            groupId, articleId, version);
451    
452                    if (Validator.isNull(article.getStructureId())) {
453                            return;
454                    }
455    
456                    try {
457                            checkStructure(article);
458                    }
459                    catch (DocumentException de) {
460                            _log.error(de, de);
461                    }
462            }
463    
464            public JournalArticle copyArticle(
465                            long userId, long groupId, String oldArticleId, String newArticleId,
466                            boolean autoArticleId, double version)
467                    throws PortalException, SystemException {
468    
469                    // Article
470    
471                    User user = userPersistence.findByPrimaryKey(userId);
472                    oldArticleId = oldArticleId.trim().toUpperCase();
473                    newArticleId = newArticleId.trim().toUpperCase();
474                    Date now = new Date();
475    
476                    JournalArticle oldArticle = journalArticlePersistence.findByG_A_V(
477                            groupId, oldArticleId, version);
478    
479                    if (autoArticleId) {
480                            newArticleId = String.valueOf(counterLocalService.increment());
481                    }
482                    else {
483                            validate(newArticleId);
484    
485                            JournalArticle newArticle = journalArticlePersistence.fetchByG_A_V(
486                                    groupId, newArticleId, version);
487    
488                            if (newArticle != null) {
489                                    throw new DuplicateArticleIdException();
490                            }
491                    }
492    
493                    long id = counterLocalService.increment();
494    
495                    long resourcePrimKey =
496                            journalArticleResourceLocalService.getArticleResourcePrimKey(
497                                    groupId, newArticleId);
498    
499                    JournalArticle newArticle = journalArticlePersistence.create(id);
500    
501                    newArticle.setResourcePrimKey(resourcePrimKey);
502                    newArticle.setGroupId(groupId);
503                    newArticle.setCompanyId(user.getCompanyId());
504                    newArticle.setUserId(user.getUserId());
505                    newArticle.setUserName(user.getFullName());
506                    newArticle.setCreateDate(now);
507                    newArticle.setModifiedDate(now);
508                    newArticle.setArticleId(newArticleId);
509                    newArticle.setVersion(JournalArticleConstants.DEFAULT_VERSION);
510                    newArticle.setTitle(oldArticle.getTitle());
511                    newArticle.setDescription(oldArticle.getDescription());
512    
513                    try {
514                            copyArticleImages(oldArticle, newArticle);
515                    }
516                    catch (Exception e) {
517                            newArticle.setContent(oldArticle.getContent());
518                    }
519    
520                    newArticle.setType(oldArticle.getType());
521                    newArticle.setStructureId(oldArticle.getStructureId());
522                    newArticle.setTemplateId(oldArticle.getTemplateId());
523                    newArticle.setDisplayDate(oldArticle.getDisplayDate());
524                    newArticle.setStatus(oldArticle.getStatus());
525                    newArticle.setExpirationDate(oldArticle.getExpirationDate());
526                    newArticle.setReviewDate(oldArticle.getReviewDate());
527                    newArticle.setIndexable(oldArticle.isIndexable());
528                    newArticle.setSmallImage(oldArticle.isSmallImage());
529                    newArticle.setSmallImageId(counterLocalService.increment());
530                    newArticle.setSmallImageURL(oldArticle.getSmallImageURL());
531    
532                    journalArticlePersistence.update(newArticle, false);
533    
534                    // Resources
535    
536                    addArticleResources(newArticle, true, true);
537    
538                    // Small image
539    
540                    if (oldArticle.getSmallImage()) {
541                            Image image = imageLocalService.getImage(
542                                    oldArticle.getSmallImageId());
543    
544                            byte[] smallBytes = image.getTextObj();
545    
546                            imageLocalService.updateImage(
547                                    newArticle.getSmallImageId(), smallBytes);
548                    }
549    
550                    // Asset
551    
552                    String[] assetTagNames = assetTagLocalService.getTagNames(
553                            JournalArticle.class.getName(), oldArticle.getResourcePrimKey());
554    
555                    updateAsset(userId, newArticle, null, assetTagNames);
556    
557                    return newArticle;
558            }
559    
560            public void deleteArticle(
561                            JournalArticle article, String articleURL,
562                            ServiceContext serviceContext)
563                    throws PortalException, SystemException {
564    
565                    if (article.isApproved() &&
566                            isLatestVersion(
567                                    article.getGroupId(), article.getArticleId(),
568                                    article.getVersion(), WorkflowConstants.STATUS_APPROVED)) {
569    
570                            updatePreviousApprovedArticle(article);
571                    }
572    
573                    // Email
574    
575                    PortletPreferences preferences =
576                            ServiceContextUtil.getPortletPreferences(serviceContext);
577    
578                    if ((preferences != null) && !article.isApproved() &&
579                            isLatestVersion(
580                                    article.getGroupId(), article.getArticleId(),
581                                    article.getVersion())) {
582    
583                            try {
584                                    sendEmail(article, articleURL, preferences, "denied");
585                            }
586                            catch (IOException ioe) {
587                                    throw new SystemException(ioe);
588                            }
589                    }
590    
591                    // Images
592    
593                    journalArticleImageLocalService.deleteImages(
594                            article.getGroupId(), article.getArticleId(), article.getVersion());
595    
596                    // Workflow
597    
598                    workflowInstanceLinkLocalService.deleteWorkflowInstanceLink(
599                            article.getCompanyId(), article.getGroupId(),
600                            JournalArticle.class.getName(), article.getResourcePrimKey());
601    
602                    int articlesCount = journalArticlePersistence.countByG_A(
603                            article.getGroupId(), article.getArticleId());
604    
605                    if (articlesCount == 1) {
606    
607                            // Ratings
608    
609                            ratingsStatsLocalService.deleteStats(
610                                    JournalArticle.class.getName(), article.getResourcePrimKey());
611    
612                            // Message boards
613    
614                            mbMessageLocalService.deleteDiscussionMessages(
615                                    JournalArticle.class.getName(), article.getResourcePrimKey());
616    
617                            // Asset
618    
619                            assetEntryLocalService.deleteEntry(
620                                    JournalArticle.class.getName(), article.getResourcePrimKey());
621    
622                            // Content searches
623    
624                            journalContentSearchLocalService.deleteArticleContentSearches(
625                                    article.getGroupId(), article.getArticleId());
626    
627                            // Small image
628    
629                            imageLocalService.deleteImage(article.getSmallImageId());
630    
631                            // Expando
632    
633                            expandoValueLocalService.deleteValues(
634                                    JournalArticle.class.getName(), article.getResourcePrimKey());
635    
636                            // Resources
637    
638                            resourceLocalService.deleteResource(
639                                    article.getCompanyId(), JournalArticle.class.getName(),
640                                    ResourceConstants.SCOPE_INDIVIDUAL,
641                                    article.getResourcePrimKey());
642    
643                            // Resource
644    
645                            try {
646                                    journalArticleResourceLocalService.deleteArticleResource(
647                                            article.getGroupId(), article.getArticleId());
648                            }
649                            catch (NoSuchArticleResourceException nsare) {
650                            }
651                    }
652    
653                    // Article
654    
655                    journalArticlePersistence.remove(article);
656            }
657    
658            public void deleteArticle(
659                            long groupId, String articleId, double version, String articleURL,
660                            ServiceContext serviceContext)
661                    throws PortalException, SystemException {
662    
663                    JournalArticle article = journalArticlePersistence.findByG_A_V(
664                            groupId, articleId, version);
665    
666                    deleteArticle(article, articleURL, serviceContext);
667            }
668    
669            public void deleteArticle(
670                            long groupId, String articleId, ServiceContext serviceContext)
671                    throws PortalException, SystemException {
672    
673                    List<JournalArticle> articles = journalArticlePersistence.findByG_A(
674                            groupId, articleId, QueryUtil.ALL_POS, QueryUtil.ALL_POS,
675                            new ArticleVersionComparator(true));
676    
677                    for (JournalArticle article : articles) {
678                            deleteArticle(article, null, serviceContext);
679                    }
680            }
681    
682            public void deleteArticles(long groupId)
683                    throws PortalException, SystemException {
684    
685                    for (JournalArticle article :
686                                    journalArticlePersistence.findByGroupId(groupId)) {
687    
688                            deleteArticle(article, null, null);
689                    }
690            }
691    
692            public JournalArticle expireArticle(
693                            long userId, long groupId, String articleId, double version,
694                            String articleURL, ServiceContext serviceContext)
695                    throws PortalException, SystemException {
696    
697                    return updateStatus(
698                            userId, groupId, articleId, version,
699                            WorkflowConstants.STATUS_EXPIRED, articleURL, serviceContext);
700            }
701    
702            public JournalArticle getArticle(long id)
703                    throws PortalException, SystemException {
704    
705                    return journalArticlePersistence.findByPrimaryKey(id);
706            }
707    
708            public JournalArticle getArticle(long groupId, String articleId)
709                    throws PortalException, SystemException {
710    
711                    // Get the latest article that is approved, if none are approved, get
712                    // the latest unapproved article
713    
714                    try {
715                            return getLatestArticle(
716                                    groupId, articleId, WorkflowConstants.STATUS_APPROVED);
717                    }
718                    catch (NoSuchArticleException nsae) {
719                            return getLatestArticle(
720                                    groupId, articleId, WorkflowConstants.STATUS_ANY);
721                    }
722            }
723    
724            public JournalArticle getArticle(
725                            long groupId, String articleId, double version)
726                    throws PortalException, SystemException {
727    
728                    return journalArticlePersistence.findByG_A_V(
729                            groupId, articleId, version);
730            }
731    
732            public JournalArticle getArticleByUrlTitle(long groupId, String urlTitle)
733                    throws PortalException, SystemException {
734    
735                    // Get the latest article that is approved, if none are approved, get
736                    // the latest unapproved article
737    
738                    try {
739                            return getLatestArticleByUrlTitle(
740                                    groupId, urlTitle, WorkflowConstants.STATUS_APPROVED);
741                    }
742                    catch (NoSuchArticleException nsae) {
743                            return getLatestArticleByUrlTitle(
744                                    groupId, urlTitle, WorkflowConstants.STATUS_PENDING);
745                    }
746            }
747    
748            public String getArticleContent(
749                            JournalArticle article, String templateId, String viewMode,
750                            String languageId, ThemeDisplay themeDisplay)
751                    throws PortalException, SystemException {
752    
753                    JournalArticleDisplay articleDisplay = getArticleDisplay(
754                            article, templateId, viewMode, languageId, 1, null, themeDisplay);
755    
756                    if (articleDisplay == null) {
757                            return StringPool.BLANK;
758                    }
759                    else {
760                            return articleDisplay.getContent();
761                    }
762            }
763    
764            public String getArticleContent(
765                            long groupId, String articleId, double version, String viewMode,
766                            String templateId, String languageId, ThemeDisplay themeDisplay)
767                    throws PortalException, SystemException {
768    
769                    JournalArticleDisplay articleDisplay = getArticleDisplay(
770                            groupId, articleId, version, templateId, viewMode, languageId,
771                            themeDisplay);
772    
773                    if (articleDisplay == null) {
774                            return StringPool.BLANK;
775                    }
776                    else {
777                            return articleDisplay.getContent();
778                    }
779            }
780    
781            public String getArticleContent(
782                            long groupId, String articleId, double version, String viewMode,
783                            String languageId, ThemeDisplay themeDisplay)
784                    throws PortalException, SystemException {
785    
786                    return getArticleContent(
787                            groupId, articleId, version, viewMode, null, languageId,
788                            themeDisplay);
789            }
790    
791            public String getArticleContent(
792                            long groupId, String articleId, String viewMode, String templateId,
793                            String languageId, ThemeDisplay themeDisplay)
794                    throws PortalException, SystemException {
795    
796                    JournalArticleDisplay articleDisplay = getArticleDisplay(
797                            groupId, articleId, templateId, viewMode, languageId, themeDisplay);
798    
799                    return articleDisplay.getContent();
800            }
801    
802            public String getArticleContent(
803                            long groupId, String articleId, String viewMode, String languageId,
804                            ThemeDisplay themeDisplay)
805                    throws PortalException, SystemException {
806    
807                    return getArticleContent(
808                            groupId, articleId, viewMode, null, languageId, themeDisplay);
809            }
810    
811            public JournalArticleDisplay getArticleDisplay(
812                            JournalArticle article, String templateId, String viewMode,
813                            String languageId, int page, String xmlRequest,
814                            ThemeDisplay themeDisplay)
815                    throws PortalException, SystemException {
816    
817                    String content = null;
818    
819                    if (page < 1) {
820                            page = 1;
821                    }
822    
823                    int numberOfPages = 1;
824                    boolean paginate = false;
825                    boolean pageFlow = false;
826    
827                    boolean cacheable = true;
828    
829                    if (Validator.isNull(xmlRequest)) {
830                            xmlRequest = "<request />";
831                    }
832    
833                    Map<String, String> tokens = JournalUtil.getTokens(
834                            article.getGroupId(), themeDisplay, xmlRequest);
835    
836                    tokens.put(
837                            "article_resource_pk",
838                            String.valueOf(article.getResourcePrimKey()));
839    
840                    String defaultTemplateId = article.getTemplateId();
841    
842                    if (article.isTemplateDriven()) {
843                            if (Validator.isNull(templateId)) {
844                                    templateId = defaultTemplateId;
845                            }
846    
847                            tokens.put("structure_id", article.getStructureId());
848                            tokens.put("template_id", templateId);
849                    }
850    
851                    String xml = article.getContent();
852    
853                    try {
854                            Document doc = null;
855    
856                            Element root = null;
857    
858                            if (article.isTemplateDriven()) {
859                                    doc = SAXReaderUtil.read(xml);
860    
861                                    root = doc.getRootElement();
862    
863                                    Document request = SAXReaderUtil.read(xmlRequest);
864    
865                                    List<Element> pages = root.elements("page");
866    
867                                    if (pages.size() > 0) {
868                                            pageFlow = true;
869    
870                                            String targetPage = request.valueOf(
871                                                    "/request/parameters/parameter[name='targetPage']/" +
872                                                            "value");
873    
874                                            Element pageEl = null;
875    
876                                            if (Validator.isNotNull(targetPage)) {
877                                                    XPath xpathSelector = SAXReaderUtil.createXPath(
878                                                            "/root/page[@id = '" + targetPage + "']");
879    
880                                                    pageEl = (Element)xpathSelector.selectSingleNode(doc);
881                                            }
882    
883                                            if (pageEl != null) {
884                                                    doc = SAXReaderUtil.createDocument(pageEl);
885    
886                                                    root = doc.getRootElement();
887    
888                                                    numberOfPages = pages.size();
889                                            }
890                                            else {
891                                                    if (page > pages.size()) {
892                                                            page = 1;
893                                                    }
894    
895                                                    pageEl = pages.get(page - 1);
896    
897                                                    doc = SAXReaderUtil.createDocument(pageEl);
898    
899                                                    root = doc.getRootElement();
900    
901                                                    numberOfPages = pages.size();
902                                                    paginate = true;
903                                            }
904                                    }
905    
906                                    root.add(request.getRootElement().createCopy());
907    
908                                    JournalUtil.addAllReservedEls(root, tokens, article);
909    
910                                    xml = JournalUtil.formatXML(doc);
911                            }
912                    }
913                    catch (DocumentException de) {
914                            throw new SystemException(de);
915                    }
916                    catch (IOException ioe) {
917                            throw new SystemException(ioe);
918                    }
919    
920                    try {
921                            if (_log.isDebugEnabled()) {
922                                    _log.debug(
923                                            "Transforming " + article.getArticleId() + " " +
924                                                    article.getVersion() + " " + languageId);
925                            }
926    
927                            String script = null;
928                            String langType = null;
929    
930                            if (article.isTemplateDriven()) {
931    
932                                    // Try with specified template first. If a template is not
933                                    // specified, use the default one. If the specified template
934                                    // does not exit, use the default one. If the default one does
935                                    // not exist, throw an exception.
936    
937                                    JournalTemplate template = null;
938    
939                                    try {
940                                            template = journalTemplatePersistence.findByG_T(
941                                                    article.getGroupId(), templateId);
942                                    }
943                                    catch (NoSuchTemplateException nste) {
944                                            if (!defaultTemplateId.equals(templateId)) {
945                                                    template = journalTemplatePersistence.findByG_T(
946                                                            article.getGroupId(), defaultTemplateId);
947                                            }
948                                            else {
949                                                    throw nste;
950                                            }
951                                    }
952    
953                                    script = template.getXsl();
954                                    langType = template.getLangType();
955                                    cacheable = template.isCacheable();
956                            }
957    
958                            content = JournalUtil.transform(
959                                    themeDisplay, tokens, viewMode, languageId, xml, script,
960                                    langType);
961    
962                            if (!pageFlow) {
963                                    String[] pieces = StringUtil.split(content, _TOKEN_PAGE_BREAK);
964    
965                                    if (pieces.length > 1) {
966                                            if (page > pieces.length) {
967                                                    page = 1;
968                                            }
969    
970                                            content = pieces[page - 1];
971                                            numberOfPages = pieces.length;
972                                            paginate = true;
973                                    }
974                            }
975                    }
976                    catch (Exception e) {
977                            throw new SystemException(e);
978                    }
979    
980                    return new JournalArticleDisplayImpl(
981                            article.getId(), article.getResourcePrimKey(), article.getGroupId(),
982                            article.getUserId(), article.getArticleId(), article.getVersion(),
983                            article.getTitle(), article.getUrlTitle(), article.getDescription(),
984                            article.getAvailableLocales(), content, article.getType(),
985                            article.getStructureId(), templateId, article.isSmallImage(),
986                            article.getSmallImageId(), article.getSmallImageURL(),
987                            numberOfPages, page, paginate, cacheable);
988            }
989    
990            public JournalArticleDisplay getArticleDisplay(
991                            long groupId, String articleId, double version, String templateId,
992                            String viewMode, String languageId, int page, String xmlRequest,
993                            ThemeDisplay themeDisplay)
994                    throws PortalException, SystemException {
995    
996                    Date now = new Date();
997    
998                    JournalArticle article = journalArticlePersistence.findByG_A_V(
999                            groupId, articleId, version);
1000    
1001                    if (article.isExpired()) {
1002                            Date expirationDate = article.getExpirationDate();
1003    
1004                            if ((expirationDate != null) && expirationDate.before(now)) {
1005                                    return null;
1006                            }
1007                    }
1008    
1009                    if (article.getDisplayDate().after(now)) {
1010                            return null;
1011                    }
1012    
1013                    return getArticleDisplay(
1014                            article, templateId, viewMode, languageId, page, xmlRequest,
1015                            themeDisplay);
1016            }
1017    
1018            public JournalArticleDisplay getArticleDisplay(
1019                            long groupId, String articleId, double version, String templateId,
1020                            String viewMode, String languageId, ThemeDisplay themeDisplay)
1021                    throws PortalException, SystemException {
1022    
1023                    return getArticleDisplay(
1024                            groupId, articleId, version, templateId, viewMode, languageId, 1,
1025                            null, themeDisplay);
1026            }
1027    
1028            public JournalArticleDisplay getArticleDisplay(
1029                            long groupId, String articleId, String viewMode, String languageId,
1030                            int page, String xmlRequest, ThemeDisplay themeDisplay)
1031                    throws PortalException, SystemException {
1032    
1033                    return getArticleDisplay(
1034                            groupId, articleId, null, viewMode, languageId, page, xmlRequest,
1035                            themeDisplay);
1036            }
1037    
1038            public JournalArticleDisplay getArticleDisplay(
1039                            long groupId, String articleId, String templateId, String viewMode,
1040                            String languageId, int page, String xmlRequest,
1041                            ThemeDisplay themeDisplay)
1042                    throws PortalException, SystemException {
1043    
1044                    JournalArticle article = getDisplayArticle(groupId, articleId);
1045    
1046                    return getArticleDisplay(
1047                            groupId, articleId, article.getVersion(), templateId, viewMode,
1048                            languageId, page, xmlRequest, themeDisplay);
1049            }
1050    
1051            public JournalArticleDisplay getArticleDisplay(
1052                            long groupId, String articleId, String templateId, String viewMode,
1053                            String languageId, ThemeDisplay themeDisplay)
1054                    throws PortalException, SystemException {
1055    
1056                    JournalArticle article = getDisplayArticle(groupId, articleId);
1057    
1058                    return getArticleDisplay(
1059                            groupId, articleId, article.getVersion(), templateId, viewMode,
1060                            languageId, themeDisplay);
1061            }
1062    
1063            public JournalArticleDisplay getArticleDisplay(
1064                            long groupId, String articleId, String viewMode, String languageId,
1065                            ThemeDisplay themeDisplay)
1066                    throws PortalException, SystemException {
1067    
1068                    return getArticleDisplay(
1069                            groupId, articleId, null, viewMode, languageId, themeDisplay);
1070            }
1071    
1072            public List<JournalArticle> getArticles() throws SystemException {
1073                    return journalArticlePersistence.findAll();
1074            }
1075    
1076            public List<JournalArticle> getArticles(long groupId)
1077                    throws SystemException {
1078    
1079                    return journalArticlePersistence.findByGroupId(groupId);
1080            }
1081    
1082            public List<JournalArticle> getArticles(long groupId, int start, int end)
1083                    throws SystemException {
1084    
1085                    return journalArticlePersistence.findByGroupId(groupId, start, end);
1086            }
1087    
1088            public List<JournalArticle> getArticles(
1089                            long groupId, int start, int end, OrderByComparator obc)
1090                    throws SystemException {
1091    
1092                    return journalArticlePersistence.findByGroupId(
1093                            groupId, start, end, obc);
1094            }
1095    
1096            public List<JournalArticle> getArticles(long groupId, String articleId)
1097                    throws SystemException {
1098    
1099                    return journalArticlePersistence.findByG_A(groupId, articleId);
1100            }
1101    
1102            public List<JournalArticle> getArticlesBySmallImageId(long smallImageId)
1103                    throws SystemException {
1104    
1105                    return journalArticlePersistence.findBySmallImageId(smallImageId);
1106            }
1107    
1108            public int getArticlesCount(long groupId) throws SystemException {
1109                    return journalArticlePersistence.countByGroupId(groupId);
1110            }
1111    
1112            public List<JournalArticle> getCompanyArticles(
1113                            long companyId, int status, int start, int end)
1114                    throws SystemException {
1115    
1116                    if (status == WorkflowConstants.STATUS_ANY) {
1117                            return journalArticlePersistence.findByCompanyId(
1118                                    companyId, start, end, new ArticleIDComparator(true));
1119                    }
1120                    else {
1121                            return journalArticlePersistence.findByC_ST(
1122                                    companyId, status, start, end, new ArticleIDComparator(true));
1123                    }
1124            }
1125    
1126            public int getCompanyArticlesCount(long companyId, int status)
1127                    throws SystemException {
1128    
1129                    if (status == WorkflowConstants.STATUS_ANY) {
1130                            return journalArticlePersistence.countByCompanyId(companyId);
1131                    }
1132                    else {
1133                            return journalArticlePersistence.countByC_ST(companyId, status);
1134                    }
1135            }
1136    
1137            public JournalArticle getDisplayArticle(long groupId, String articleId)
1138                    throws PortalException, SystemException {
1139    
1140                    List<JournalArticle> articles = journalArticlePersistence.findByG_A_ST(
1141                            groupId, articleId, WorkflowConstants.STATUS_APPROVED);
1142    
1143                    if (articles.size() == 0) {
1144                            throw new NoSuchArticleException(
1145                                    "No approved JournalArticle with the key {groupId=" + groupId +
1146                                            ", " + "articleId=" + articleId + "}");
1147    
1148                    }
1149    
1150                    Date now = new Date();
1151    
1152                    for (int i = 0; i < articles.size(); i++) {
1153                            JournalArticle article = articles.get(i);
1154    
1155                            Date expirationDate = article.getExpirationDate();
1156    
1157                            if (article.getDisplayDate().before(now) &&
1158                                    ((expirationDate == null) || expirationDate.after(now))) {
1159    
1160                                    return article;
1161                            }
1162                    }
1163    
1164                    return articles.get(0);
1165            }
1166    
1167            public JournalArticle getLatestArticle(long resourcePrimKey)
1168                    throws PortalException, SystemException {
1169    
1170                    return getLatestArticle(resourcePrimKey, WorkflowConstants.STATUS_ANY);
1171            }
1172    
1173            public JournalArticle getLatestArticle(long resourcePrimKey, int status)
1174                    throws PortalException, SystemException {
1175    
1176                    return getLatestArticle(resourcePrimKey, status, true);
1177            }
1178    
1179            public JournalArticle getLatestArticle(
1180                            long resourcePrimKey, int status, boolean preferApproved)
1181                    throws PortalException, SystemException {
1182    
1183                    List<JournalArticle> articles = null;
1184    
1185                    OrderByComparator orderByComparator = new ArticleVersionComparator();
1186    
1187                    if (status == WorkflowConstants.STATUS_ANY) {
1188                            if (preferApproved) {
1189                                    articles = journalArticlePersistence.findByR_ST(
1190                                            resourcePrimKey, WorkflowConstants.STATUS_APPROVED, 0, 1,
1191                                            orderByComparator);
1192                            }
1193    
1194                            if ((articles == null) || (articles.size() == 0)) {
1195                                    articles = journalArticlePersistence.findByResourcePrimKey(
1196                                            resourcePrimKey, 0, 1, orderByComparator);
1197                            }
1198                    }
1199                    else {
1200                            articles = journalArticlePersistence.findByR_ST(
1201                                    resourcePrimKey, status, 0, 1, orderByComparator);
1202                    }
1203    
1204                    if (articles.size() == 0) {
1205                            throw new NoSuchArticleException(
1206                                    "No JournalArticle with the key {resourcePrimKey=" +
1207                                            resourcePrimKey + "}");
1208                    }
1209    
1210                    return articles.get(0);
1211            }
1212    
1213            public JournalArticle getLatestArticle(long groupId, String articleId)
1214                    throws PortalException, SystemException {
1215    
1216                    return getLatestArticle(
1217                            groupId, articleId, WorkflowConstants.STATUS_ANY);
1218            }
1219    
1220            public JournalArticle getLatestArticle(
1221                            long groupId, String articleId, int status)
1222                    throws PortalException, SystemException {
1223    
1224                    List<JournalArticle> articles = null;
1225    
1226                    OrderByComparator orderByComparator = new ArticleVersionComparator();
1227    
1228                    if (status == WorkflowConstants.STATUS_ANY) {
1229                            articles = journalArticlePersistence.findByG_A(
1230                                    groupId, articleId, 0, 1, orderByComparator);
1231                    }
1232                    else {
1233                            articles = journalArticlePersistence.findByG_A_ST(
1234                                    groupId, articleId, status, 0, 1, orderByComparator);
1235                    }
1236    
1237                    if (articles.size() == 0) {
1238                            throw new NoSuchArticleException(
1239                                    "No JournalArticle with the key {groupId=" + groupId +
1240                                            ", articleId=" + articleId + ", status=" + status + "}");
1241                    }
1242    
1243                    return articles.get(0);
1244            }
1245    
1246            public JournalArticle getLatestArticleByUrlTitle(
1247                            long groupId, String urlTitle, int status)
1248                    throws PortalException, SystemException {
1249    
1250                    List<JournalArticle> articles = null;
1251    
1252                    OrderByComparator orderByComparator = new ArticleVersionComparator();
1253    
1254                    if (status == WorkflowConstants.STATUS_ANY) {
1255                            articles = journalArticlePersistence.findByG_UT(
1256                                    groupId, urlTitle, 0, 1, orderByComparator);
1257                    }
1258                    else {
1259                            articles = journalArticlePersistence.findByG_UT_ST(
1260                                    groupId, urlTitle, status, 0, 1, orderByComparator);
1261                    }
1262    
1263                    if (articles.size() == 0) {
1264                            throw new NoSuchArticleException(
1265                                    "No JournalArticle with the key {groupId=" + groupId +
1266                                            ", urlTitle=" + urlTitle + ", status=" + status + "}");
1267                    }
1268    
1269                    return articles.get(0);
1270            }
1271    
1272            public double getLatestVersion(long groupId, String articleId)
1273                    throws PortalException, SystemException {
1274    
1275                    JournalArticle article = getLatestArticle(groupId, articleId);
1276    
1277                    return article.getVersion();
1278            }
1279    
1280            public double getLatestVersion(
1281                            long groupId, String articleId, int status)
1282                    throws PortalException, SystemException {
1283    
1284                    JournalArticle article = getLatestArticle(groupId, articleId, status);
1285    
1286                    return article.getVersion();
1287            }
1288    
1289            public List<JournalArticle> getStructureArticles(
1290                            long groupId, String structureId)
1291                    throws SystemException {
1292    
1293                    return journalArticlePersistence.findByG_S(groupId, structureId);
1294            }
1295    
1296            public List<JournalArticle> getStructureArticles(
1297                            long groupId, String structureId, int start, int end,
1298                            OrderByComparator obc)
1299                    throws SystemException {
1300    
1301                    return journalArticlePersistence.findByG_S(
1302                            groupId, structureId, start, end, obc);
1303            }
1304    
1305            public int getStructureArticlesCount(long groupId, String structureId)
1306                    throws SystemException {
1307    
1308                    return journalArticlePersistence.countByG_S(groupId, structureId);
1309            }
1310    
1311            public List<JournalArticle> getTemplateArticles(
1312                            long groupId, String templateId)
1313                    throws SystemException {
1314    
1315                    return journalArticlePersistence.findByG_T(groupId, templateId);
1316            }
1317    
1318            public List<JournalArticle> getTemplateArticles(
1319                            long groupId, String templateId, int start, int end,
1320                            OrderByComparator obc)
1321                    throws SystemException {
1322    
1323                    return journalArticlePersistence.findByG_T(
1324                            groupId, templateId, start, end, obc);
1325            }
1326    
1327            public int getTemplateArticlesCount(long groupId, String templateId)
1328                    throws SystemException {
1329    
1330                    return journalArticlePersistence.countByG_T(groupId, templateId);
1331            }
1332    
1333            public boolean hasArticle(long groupId, String articleId)
1334                    throws SystemException {
1335    
1336                    try {
1337                            getArticle(groupId, articleId);
1338    
1339                            return true;
1340                    }
1341                    catch (PortalException pe) {
1342                            return false;
1343                    }
1344            }
1345    
1346            public boolean isLatestVersion(
1347                            long groupId, String articleId, double version)
1348                    throws PortalException, SystemException {
1349    
1350                    if (getLatestVersion(groupId, articleId) == version) {
1351                            return true;
1352                    }
1353                    else {
1354                            return false;
1355                    }
1356            }
1357    
1358            public boolean isLatestVersion(
1359                            long groupId, String articleId, double version, int status)
1360                    throws PortalException, SystemException {
1361    
1362                    if (getLatestVersion(groupId, articleId, status) == version) {
1363                            return true;
1364                    }
1365                    else {
1366                            return false;
1367                    }
1368            }
1369    
1370            public JournalArticle removeArticleLocale(
1371                            long groupId, String articleId, double version, String languageId)
1372                    throws PortalException, SystemException {
1373    
1374                    JournalArticle article = journalArticlePersistence.findByG_A_V(
1375                            groupId, articleId, version);
1376    
1377                    String content = article.getContent();
1378    
1379                    if (article.isTemplateDriven()) {
1380                            content = JournalUtil.removeArticleLocale(content, languageId);
1381                    }
1382                    else {
1383                            content = LocalizationUtil.removeLocalization(
1384                                    content, "static-content", languageId, true);
1385                    }
1386    
1387                    article.setContent(content);
1388    
1389                    journalArticlePersistence.update(article, false);
1390    
1391                    return article;
1392            }
1393    
1394            public List<JournalArticle> search(
1395                            long companyId, long groupId, String keywords, Double version,
1396                            String type, String structureId, String templateId,
1397                            Date displayDateGT, Date displayDateLT, int status, Date reviewDate,
1398                            int start, int end, OrderByComparator obc)
1399                    throws SystemException {
1400    
1401                    return journalArticleFinder.findByKeywords(
1402                            companyId, groupId, keywords, version, type, structureId,
1403                            templateId, displayDateGT, displayDateLT, status, reviewDate, start,
1404                            end, obc);
1405            }
1406    
1407            public List<JournalArticle> search(
1408                            long companyId, long groupId, String articleId, Double version,
1409                            String title, String description, String content, String type,
1410                            String structureId, String templateId, Date displayDateGT,
1411                            Date displayDateLT, int status, Date reviewDate,
1412                            boolean andOperator, int start, int end, OrderByComparator obc)
1413                    throws SystemException {
1414    
1415                    return journalArticleFinder.findByC_G_A_V_T_D_C_T_S_T_D_S_R(
1416                            companyId, groupId, articleId, version, title, description, content,
1417                            type, structureId, templateId, displayDateGT, displayDateLT,
1418                            status, reviewDate, andOperator, start, end, obc);
1419            }
1420    
1421            public List<JournalArticle> search(
1422                            long companyId, long groupId, String articleId, Double version,
1423                            String title, String description, String content, String type,
1424                            String[] structureIds, String[] templateIds, Date displayDateGT,
1425                            Date displayDateLT, int status, Date reviewDate,
1426                            boolean andOperator, int start, int end, OrderByComparator obc)
1427                    throws SystemException {
1428    
1429                    return journalArticleFinder.findByC_G_A_V_T_D_C_T_S_T_D_S_R(
1430                            companyId, groupId, articleId, version, title, description, content,
1431                            type, structureIds, templateIds, displayDateGT, displayDateLT,
1432                            status, reviewDate, andOperator, start, end, obc);
1433            }
1434    
1435            public int searchCount(
1436                            long companyId, long groupId, String keywords, Double version,
1437                            String type, String structureId, String templateId,
1438                            Date displayDateGT, Date displayDateLT, int status, Date reviewDate)
1439                    throws SystemException {
1440    
1441                    return journalArticleFinder.countByKeywords(
1442                            companyId, groupId, keywords, version, type, structureId,
1443                            templateId, displayDateGT, displayDateLT, status, reviewDate);
1444            }
1445    
1446            public int searchCount(
1447                            long companyId, long groupId, String articleId, Double version,
1448                            String title, String description, String content, String type,
1449                            String structureId, String templateId, Date displayDateGT,
1450                            Date displayDateLT, int status, Date reviewDate,
1451                            boolean andOperator)
1452                    throws SystemException {
1453    
1454                    return journalArticleFinder.countByC_G_A_V_T_D_C_T_S_T_D_S_R(
1455                            companyId, groupId, articleId, version, title, description, content,
1456                            type, structureId, templateId, displayDateGT, displayDateLT,
1457                            status, reviewDate, andOperator);
1458            }
1459    
1460            public int searchCount(
1461                            long companyId, long groupId, String articleId, Double version,
1462                            String title, String description, String content, String type,
1463                            String[] structureIds, String[] templateIds, Date displayDateGT,
1464                            Date displayDateLT, int status, Date reviewDate,
1465                            boolean andOperator)
1466                    throws SystemException {
1467    
1468                    return journalArticleFinder.countByC_G_A_V_T_D_C_T_S_T_D_S_R(
1469                            companyId, groupId, articleId, version, title, description, content,
1470                            type, structureIds, templateIds, displayDateGT, displayDateLT,
1471                            status, reviewDate, andOperator);
1472            }
1473    
1474            public JournalArticle updateArticle(
1475                            long userId, long groupId, String articleId, double version,
1476                            String content)
1477                    throws PortalException, SystemException {
1478    
1479                    User user = userPersistence.findByPrimaryKey(userId);
1480    
1481                    JournalArticle article = journalArticlePersistence.findByG_A_V(
1482                            groupId, articleId, version);
1483    
1484                    Date displayDate = article.getDisplayDate();
1485    
1486                    int displayDateMonth = 0;
1487                    int displayDateDay = 0;
1488                    int displayDateYear = 0;
1489                    int displayDateHour = 0;
1490                    int displayDateMinute = 0;
1491    
1492                    if (displayDate != null) {
1493                            Calendar displayCal = CalendarFactoryUtil.getCalendar(
1494                                    user.getTimeZone());
1495    
1496                            displayCal.setTime(displayDate);
1497    
1498                            displayDateMonth = displayCal.get(Calendar.MONTH);
1499                            displayDateDay = displayCal.get(Calendar.DATE);
1500                            displayDateYear = displayCal.get(Calendar.YEAR);
1501                            displayDateHour = displayCal.get(Calendar.HOUR);
1502                            displayDateMinute = displayCal.get(Calendar.MINUTE);
1503    
1504                            if (displayCal.get(Calendar.AM_PM) == Calendar.PM) {
1505                                    displayDateHour += 12;
1506                            }
1507                    }
1508    
1509                    Date expirationDate = article.getExpirationDate();
1510    
1511                    int expirationDateMonth = 0;
1512                    int expirationDateDay = 0;
1513                    int expirationDateYear = 0;
1514                    int expirationDateHour = 0;
1515                    int expirationDateMinute = 0;
1516                    boolean neverExpire = true;
1517    
1518                    if (expirationDate != null) {
1519                            Calendar expirationCal = CalendarFactoryUtil.getCalendar(
1520                                    user.getTimeZone());
1521    
1522                            expirationCal.setTime(expirationDate);
1523    
1524                            expirationDateMonth = expirationCal.get(Calendar.MONTH);
1525                            expirationDateDay = expirationCal.get(Calendar.DATE);
1526                            expirationDateYear = expirationCal.get(Calendar.YEAR);
1527                            expirationDateHour = expirationCal.get(Calendar.HOUR);
1528                            expirationDateMinute = expirationCal.get(Calendar.MINUTE);
1529                            neverExpire = false;
1530    
1531                            if (expirationCal.get(Calendar.AM_PM) == Calendar.PM) {
1532                                    expirationDateHour += 12;
1533                            }
1534                    }
1535    
1536                    Date reviewDate = article.getReviewDate();
1537    
1538                    int reviewDateMonth = 0;
1539                    int reviewDateDay = 0;
1540                    int reviewDateYear = 0;
1541                    int reviewDateHour = 0;
1542                    int reviewDateMinute = 0;
1543                    boolean neverReview = true;
1544    
1545                    if (reviewDate != null) {
1546                            Calendar reviewCal = CalendarFactoryUtil.getCalendar(
1547                                    user.getTimeZone());
1548    
1549                            reviewCal.setTime(reviewDate);
1550    
1551                            reviewDateMonth = reviewCal.get(Calendar.MONTH);
1552                            reviewDateDay = reviewCal.get(Calendar.DATE);
1553                            reviewDateYear = reviewCal.get(Calendar.YEAR);
1554                            reviewDateHour = reviewCal.get(Calendar.HOUR);
1555                            reviewDateMinute = reviewCal.get(Calendar.MINUTE);
1556                            neverReview = false;
1557    
1558                            if (reviewCal.get(Calendar.AM_PM) == Calendar.PM) {
1559                                    reviewDateHour += 12;
1560                            }
1561                    }
1562    
1563                    PortletPreferencesIds portletPreferencesIds = new PortletPreferencesIds(
1564                            article.getCompanyId(), PortletKeys.PREFS_OWNER_ID_DEFAULT,
1565                            PortletKeys.PREFS_OWNER_TYPE_LAYOUT, PortletKeys.PREFS_PLID_SHARED,
1566                            PortletKeys.JOURNAL);
1567    
1568                    ServiceContext serviceContext = new ServiceContext();
1569    
1570                    serviceContext.setPortletPreferencesIds(portletPreferencesIds);
1571    
1572                    return updateArticle(
1573                            userId, groupId, articleId, version, article.getTitle(),
1574                            article.getDescription(), content, article.getType(),
1575                            article.getStructureId(), article.getTemplateId(), displayDateMonth,
1576                            displayDateDay, displayDateYear, displayDateHour, displayDateMinute,
1577                            expirationDateMonth, expirationDateDay, expirationDateYear,
1578                            expirationDateHour, expirationDateMinute, neverExpire,
1579                            reviewDateMonth, reviewDateDay, reviewDateYear, reviewDateHour,
1580                            reviewDateMinute, neverReview, article.getIndexable(),
1581                            article.isSmallImage(), article.getSmallImageURL(), null, null,
1582                            null, serviceContext);
1583            }
1584    
1585            public JournalArticle updateArticle(
1586                            long userId, long groupId, String articleId, double version,
1587                            String title, String description, String content, String type,
1588                            String structureId, String templateId, int displayDateMonth,
1589                            int displayDateDay, int displayDateYear, int displayDateHour,
1590                            int displayDateMinute, int expirationDateMonth,
1591                            int expirationDateDay, int expirationDateYear,
1592                            int expirationDateHour, int expirationDateMinute,
1593                            boolean neverExpire, int reviewDateMonth, int reviewDateDay,
1594                            int reviewDateYear, int reviewDateHour, int reviewDateMinute,
1595                            boolean neverReview, boolean indexable, boolean smallImage,
1596                            String smallImageURL, File smallFile, Map<String, byte[]> images,
1597                            String articleURL, ServiceContext serviceContext)
1598                    throws PortalException, SystemException {
1599    
1600                    // Article
1601    
1602                    User user = userPersistence.findByPrimaryKey(userId);
1603                    articleId = articleId.trim().toUpperCase();
1604    
1605                    Date displayDate = PortalUtil.getDate(
1606                            displayDateMonth, displayDateDay, displayDateYear,
1607                            displayDateHour, displayDateMinute, user.getTimeZone(),
1608                            new ArticleDisplayDateException());
1609    
1610                    Date expirationDate = null;
1611    
1612                    if (!neverExpire) {
1613                            expirationDate = PortalUtil.getDate(
1614                                    expirationDateMonth, expirationDateDay, expirationDateYear,
1615                                    expirationDateHour, expirationDateMinute, user.getTimeZone(),
1616                                    new ArticleExpirationDateException());
1617                    }
1618    
1619                    Date reviewDate = null;
1620    
1621                    if (!neverReview) {
1622                            reviewDate = PortalUtil.getDate(
1623                                    reviewDateMonth, reviewDateDay, reviewDateYear, reviewDateHour,
1624                                    reviewDateMinute, user.getTimeZone(),
1625                                    new ArticleReviewDateException());
1626                    }
1627    
1628                    byte[] smallBytes = null;
1629    
1630                    try {
1631                            smallBytes = FileUtil.getBytes(smallFile);
1632                    }
1633                    catch (IOException ioe) {
1634                    }
1635    
1636                    Date now = new Date();
1637    
1638                    validate(
1639                            groupId, title, content, type, structureId, templateId, smallImage,
1640                            smallImageURL, smallFile, smallBytes);
1641    
1642                    JournalArticle oldArticle = null;
1643                    double oldVersion = 0;
1644    
1645                    boolean incrementVersion = false;
1646    
1647                    boolean imported = GetterUtil.getBoolean(
1648                            serviceContext.getAttribute("imported"));
1649    
1650                    if (imported) {
1651                            oldArticle = getArticle(groupId, articleId, version);
1652                            oldVersion = version;
1653                    }
1654                    else {
1655                            oldArticle = getLatestArticle(
1656                                    groupId, articleId, WorkflowConstants.STATUS_ANY);
1657    
1658                            oldVersion = oldArticle.getVersion();
1659    
1660                            if ((version > 0) && (version != oldVersion)) {
1661                                    throw new ArticleVersionException();
1662                            }
1663    
1664                            if (oldArticle.isApproved() || oldArticle.isExpired()) {
1665                                    incrementVersion = true;
1666                            }
1667                    }
1668    
1669                    JournalArticle article = null;
1670    
1671                    if (incrementVersion) {
1672                            double newVersion = MathUtil.format(oldVersion + 0.1, 1, 1);
1673    
1674                            long id = counterLocalService.increment();
1675    
1676                            article = journalArticlePersistence.create(id);
1677    
1678                            article.setResourcePrimKey(oldArticle.getResourcePrimKey());
1679                            article.setGroupId(oldArticle.getGroupId());
1680                            article.setCompanyId(user.getCompanyId());
1681                            article.setUserId(user.getUserId());
1682                            article.setUserName(user.getFullName());
1683                            article.setCreateDate(serviceContext.getModifiedDate(now));
1684                            article.setArticleId(articleId);
1685                            article.setVersion(newVersion);
1686                            article.setSmallImageId(oldArticle.getSmallImageId());
1687                    }
1688                    else {
1689                            article = oldArticle;
1690                    }
1691    
1692                    content = format(
1693                            groupId, articleId, article.getVersion(), incrementVersion,
1694                            content, structureId, images);
1695    
1696                    article.setModifiedDate(serviceContext.getModifiedDate(now));
1697                    article.setTitle(title);
1698                    article.setUrlTitle(
1699                            getUniqueUrlTitle(article.getId(), groupId, articleId, title));
1700                    article.setDescription(description);
1701                    article.setContent(content);
1702                    article.setType(type);
1703                    article.setStructureId(structureId);
1704                    article.setTemplateId(templateId);
1705                    article.setDisplayDate(displayDate);
1706    
1707                    if (oldArticle.isPending()) {
1708                            article.setStatus(oldArticle.getStatus());
1709                    }
1710                    else if ((expirationDate == null) || expirationDate.after(now)) {
1711                            article.setStatus(WorkflowConstants.STATUS_DRAFT);
1712                    }
1713                    else {
1714                            article.setStatus(WorkflowConstants.STATUS_EXPIRED);
1715                    }
1716    
1717                    article.setExpirationDate(expirationDate);
1718                    article.setReviewDate(reviewDate);
1719                    article.setIndexable(indexable);
1720                    article.setSmallImage(smallImage);
1721    
1722                    if (article.getSmallImageId() == 0) {
1723                            article.setSmallImageId(counterLocalService.increment());
1724                    }
1725    
1726                    article.setSmallImageURL(smallImageURL);
1727    
1728                    journalArticlePersistence.update(article, false);
1729    
1730                    // Asset
1731    
1732                    long[] assetCategoryIds = serviceContext.getAssetCategoryIds();
1733                    String[] assetTagNames = serviceContext.getAssetTagNames();
1734    
1735                    updateAsset(userId, article, assetCategoryIds, assetTagNames);
1736    
1737                    // Expando
1738    
1739                    ExpandoBridge expandoBridge = article.getExpandoBridge();
1740    
1741                    expandoBridge.setAttributes(serviceContext);
1742    
1743                    // Small image
1744    
1745                    saveImages(
1746                            smallImage, article.getSmallImageId(), smallFile, smallBytes);
1747    
1748                    // Email
1749    
1750                    PortletPreferences preferences =
1751                            ServiceContextUtil.getPortletPreferences(serviceContext);
1752    
1753                    // Workflow
1754    
1755                    if (serviceContext.getWorkflowAction() ==
1756                                    WorkflowConstants.ACTION_PUBLISH) {
1757    
1758                            try {
1759                                    sendEmail(article, articleURL, preferences, "requested");
1760                            }
1761                            catch (IOException ioe) {
1762                                    throw new SystemException(ioe);
1763                            }
1764    
1765                            WorkflowHandlerRegistryUtil.startWorkflowInstance(
1766                                    user.getCompanyId(), groupId, userId,
1767                                    JournalArticle.class.getName(), article.getResourcePrimKey(),
1768                                    article, serviceContext);
1769                    }
1770    
1771                    return article;
1772            }
1773    
1774            public void updateAsset(
1775                            long userId, JournalArticle article, long[] assetCategoryIds,
1776                            String[] assetTagNames)
1777                    throws PortalException, SystemException {
1778    
1779                    // Get the earliest display date and latest expiration date among
1780                    // all article versions
1781    
1782                    Date[] dateInterval = getDateInterval(
1783                            article.getGroupId(), article.getArticleId(),
1784                            article.getDisplayDate(), article.getExpirationDate());
1785    
1786                    Date displayDate = dateInterval[0];
1787                    Date expirationDate = dateInterval[1];
1788    
1789                    boolean visible = article.isApproved();
1790    
1791                    boolean addDraftAssetEntry = false;
1792    
1793                    if (!article.isApproved() &&
1794                            (article.getVersion() != JournalArticleConstants.DEFAULT_VERSION)) {
1795    
1796                            int approvedArticlesCount =
1797                                    journalArticlePersistence.countByG_A_ST(
1798                                            article.getGroupId(), article.getArticleId(),
1799                                            WorkflowConstants.STATUS_APPROVED);
1800    
1801                            if (approvedArticlesCount > 0) {
1802                                    addDraftAssetEntry = true;
1803                            }
1804                    }
1805    
1806                    if (addDraftAssetEntry) {
1807                            assetEntryLocalService.updateEntry(
1808                                    userId, article.getGroupId(), JournalArticle.class.getName(),
1809                                    article.getPrimaryKey(), article.getUuid(), assetCategoryIds,
1810                                    assetTagNames, false, null, null, displayDate, expirationDate,
1811                                    ContentTypes.TEXT_HTML, article.getTitle(),
1812                                    article.getDescription(), null, null, 0, 0, null, false);
1813                    }
1814                    else {
1815                            assetEntryLocalService.updateEntry(
1816                                    userId, article.getGroupId(), JournalArticle.class.getName(),
1817                                    article.getResourcePrimKey(), article.getUuid(),
1818                                    assetCategoryIds, assetTagNames, visible, null, null,
1819                                    displayDate, expirationDate, ContentTypes.TEXT_HTML,
1820                                    article.getTitle(), article.getDescription(), null, null, 0, 0,
1821                                    null, false);
1822                    }
1823            }
1824    
1825            public JournalArticle updateContent(
1826                            long groupId, String articleId, double version, String content)
1827                    throws PortalException, SystemException {
1828    
1829                    JournalArticle article = journalArticlePersistence.findByG_A_V(
1830                            groupId, articleId, version);
1831    
1832                    article.setContent(content);
1833    
1834                    journalArticlePersistence.update(article, false);
1835    
1836                    return article;
1837            }
1838    
1839            public JournalArticle updateStatus(
1840                            long userId, JournalArticle article, int status, String articleURL,
1841                            ServiceContext serviceContext)
1842                    throws PortalException, SystemException {
1843    
1844                    User user = userPersistence.findByPrimaryKey(userId);
1845                    Date now = new Date();
1846    
1847                    int oldStatus = article.getStatus();
1848    
1849                    // Article
1850    
1851                    article.setModifiedDate(serviceContext.getModifiedDate(now));
1852                    article.setStatus(status);
1853                    article.setStatusByUserId(user.getUserId());
1854                    article.setStatusByUserName(user.getFullName());
1855                    article.setStatusDate(serviceContext.getModifiedDate(now));
1856    
1857                    if ((status == WorkflowConstants.STATUS_APPROVED) &&
1858                            (article.getExpirationDate() != null) &&
1859                            (article.getExpirationDate().before(now))) {
1860    
1861                            article.setExpirationDate(null);
1862                    }
1863    
1864                    if (status == WorkflowConstants.STATUS_EXPIRED) {
1865                            article.setExpirationDate(now);
1866                    }
1867    
1868                    journalArticlePersistence.update(article, false);
1869    
1870                    if (isLatestVersion(
1871                                    article.getGroupId(), article.getArticleId(),
1872                                    article.getVersion())) {
1873    
1874                            if (status == WorkflowConstants.STATUS_APPROVED) {
1875                                    updateUrlTitles(
1876                                            article.getGroupId(), article.getArticleId(),
1877                                            article.getUrlTitle());
1878    
1879                                    // Asset
1880    
1881                                    if ((oldStatus != WorkflowConstants.STATUS_APPROVED) &&
1882                                            (article.getVersion() !=
1883                                                    JournalArticleConstants.DEFAULT_VERSION)) {
1884    
1885                                            AssetEntry draftAssetEntry = null;
1886    
1887                                            try {
1888                                                    draftAssetEntry = assetEntryLocalService.getEntry(
1889                                                            JournalArticle.class.getName(),
1890                                                            article.getPrimaryKey());
1891    
1892                                                    Date[] dateInterval = getDateInterval(
1893                                                            article.getGroupId(), article.getArticleId(),
1894                                                            article.getDisplayDate(),
1895                                                            article.getExpirationDate());
1896    
1897                                                    Date displayDate = dateInterval[0];
1898                                                    Date expirationDate = dateInterval[1];
1899    
1900                                                    long[] assetCategoryIds =
1901                                                            draftAssetEntry.getCategoryIds();
1902                                                    String[] assetTagNames = draftAssetEntry.getTagNames();
1903    
1904                                                    assetEntryLocalService.updateEntry(
1905                                                            userId, article.getGroupId(),
1906                                                            JournalArticle.class.getName(),
1907                                                            article.getResourcePrimKey(), article.getUuid(),
1908                                                            assetCategoryIds, assetTagNames, true, null, null,
1909                                                            displayDate, expirationDate, ContentTypes.TEXT_HTML,
1910                                                            article.getTitle(), article.getDescription(), null,
1911                                                            null, 0, 0, null, false);
1912    
1913                                                    assetEntryLocalService.deleteEntry(
1914                                                            JournalArticle.class.getName(),
1915                                                            article.getPrimaryKey());
1916                                            }
1917                                            catch (NoSuchEntryException nsee) {
1918                                            }
1919                                    }
1920    
1921                                    assetEntryLocalService.updateVisible(
1922                                            JournalArticle.class.getName(),
1923                                            article.getResourcePrimKey(), true);
1924    
1925                                    // Expando
1926    
1927                                    ExpandoBridge expandoBridge = article.getExpandoBridge();
1928    
1929                                    expandoBridge.setAttributes(serviceContext);
1930    
1931                                    // Indexer
1932    
1933                                    Indexer indexer = IndexerRegistryUtil.getIndexer(
1934                                            JournalArticle.class);
1935    
1936                                    indexer.reindex(article);
1937                            }
1938                            else if (oldStatus == WorkflowConstants.STATUS_APPROVED) {
1939                                    updatePreviousApprovedArticle(article);
1940                            }
1941                    }
1942    
1943                    // Email
1944    
1945                    if ((oldStatus == WorkflowConstants.STATUS_PENDING) &&
1946                            ((status == WorkflowConstants.STATUS_APPROVED) ||
1947                             (status == WorkflowConstants.STATUS_DENIED))) {
1948    
1949                            String msg = "granted";
1950    
1951                            if (status == WorkflowConstants.STATUS_DENIED) {
1952                                    msg = "denied";
1953                            }
1954    
1955                            try {
1956                                    PortletPreferences preferences =
1957                                            ServiceContextUtil.getPortletPreferences(serviceContext);
1958    
1959                                    sendEmail(article, articleURL, preferences, msg);
1960                            }
1961                            catch (Exception e) {
1962                                    _log.error(
1963                                            "Unable to send email to notify the change of status " +
1964                                                    " to " + msg + " for article " + article.getId() +
1965                                                            ": " + e.getMessage());
1966                            }
1967                    }
1968    
1969                    // Subscriptions
1970    
1971                    notifySubscribers(article, serviceContext);
1972    
1973                    return article;
1974            }
1975    
1976            public JournalArticle updateStatus(
1977                            long userId, long classPK, int status,
1978                            ServiceContext serviceContext)
1979                    throws PortalException, SystemException {
1980    
1981                    JournalArticle article = getArticle(classPK);
1982    
1983                    return updateStatus(userId, article, status, null, serviceContext);
1984            }
1985    
1986            public JournalArticle updateStatus(
1987                            long userId, long groupId, String articleId, double version,
1988                            int status, String articleURL, ServiceContext serviceContext)
1989                    throws PortalException, SystemException {
1990    
1991                    JournalArticle article = journalArticlePersistence.findByG_A_V(
1992                            groupId, articleId, version);
1993    
1994                    return updateStatus(
1995                            userId, article, status, articleURL, serviceContext);
1996            }
1997    
1998            protected void checkStructure(Document contentDoc, Element root)
1999                    throws PortalException {
2000    
2001                    for (Element el : root.elements()) {
2002                            checkStructureField(el, contentDoc);
2003    
2004                            checkStructure(contentDoc, el);
2005                    }
2006            }
2007    
2008            protected void checkStructure(JournalArticle article)
2009                    throws DocumentException, PortalException, SystemException {
2010    
2011                    JournalStructure structure = journalStructurePersistence.findByG_S(
2012                            article.getGroupId(), article.getStructureId());
2013    
2014                    String content = GetterUtil.getString(article.getContent());
2015    
2016                    Document contentDoc = SAXReaderUtil.read(content);
2017                    Document xsdDoc = SAXReaderUtil.read(structure.getXsd());
2018    
2019                    try {
2020                            checkStructure(contentDoc, xsdDoc.getRootElement());
2021                    }
2022                    catch (StructureXsdException sxsde) {
2023                            long groupId = article.getGroupId();
2024                            String articleId = article.getArticleId();
2025                            double version = article.getVersion();
2026    
2027                            if (_log.isWarnEnabled()) {
2028                                    _log.warn(
2029                                            "Article {groupId=" + groupId + ", articleId=" +
2030                                                    articleId + ", version=" + version +
2031                                                            "} has content that does not match its " +
2032                                                                    "structure: " + sxsde.getMessage());
2033                            }
2034                    }
2035            }
2036    
2037            protected void checkStructureField(Element el, Document contentDoc)
2038                    throws PortalException {
2039    
2040                    StringBuilder elPath = new StringBuilder();
2041    
2042                    elPath.append(el.attributeValue("name"));
2043    
2044                    Element elParent = el.getParent();
2045    
2046                    for (;;) {
2047                            if ((elParent == null) ||
2048                                    (elParent.getName().equals("root"))) {
2049    
2050                                    break;
2051                            }
2052    
2053                            elPath.insert(
2054                                    0, elParent.attributeValue("name") + StringPool.COMMA);
2055    
2056                            elParent = elParent.getParent();
2057                    }
2058    
2059                    String[] elPathNames = StringUtil.split(elPath.toString());
2060    
2061                    Element contentEl = contentDoc.getRootElement();
2062    
2063                    for (String _elPathName : elPathNames) {
2064                            boolean foundEl = false;
2065    
2066                            for (Element tempEl : contentEl.elements()) {
2067                                    if (_elPathName.equals(
2068                                                    tempEl.attributeValue("name", StringPool.BLANK))) {
2069    
2070                                            contentEl = tempEl;
2071                                            foundEl = true;
2072    
2073                                            break;
2074                                    }
2075                            }
2076    
2077                            if (!foundEl) {
2078                                    String elType = contentEl.attributeValue(
2079                                            "type", StringPool.BLANK);
2080    
2081                                    if (!elType.equals("list") && !elType.equals("multi-list")) {
2082                                            throw new StructureXsdException(elPath.toString());
2083                                    }
2084    
2085                                    break;
2086                            }
2087                    }
2088            }
2089    
2090            protected void copyArticleImages(
2091                            JournalArticle oldArticle, JournalArticle newArticle)
2092                    throws Exception {
2093    
2094                    Document contentDoc = SAXReaderUtil.read(oldArticle.getContent());
2095    
2096                    XPath xpathSelector = SAXReaderUtil.createXPath(
2097                            "//dynamic-element[@type='image']");
2098    
2099                    List<Node> imageNodes = xpathSelector.selectNodes(contentDoc);
2100    
2101                    for (Node imageNode : imageNodes) {
2102                            Element imageEl = (Element)imageNode;
2103    
2104                            String instanceId = imageEl.attributeValue("instance-id");
2105                            String name = imageEl.attributeValue("name");
2106    
2107                            List<Element> dynamicContentEls = imageEl.elements(
2108                                    "dynamic-content");
2109    
2110                            for (Element dynamicContentEl : dynamicContentEls) {
2111                                    long imageId = GetterUtil.getLong(
2112                                            dynamicContentEl.attributeValue("id"));
2113                                    String languageId = dynamicContentEl.attributeValue(
2114                                            "language-id");
2115    
2116                                    Image oldImage = null;
2117    
2118                                    try {
2119                                            oldImage = imageLocalService.getImage(imageId);
2120                                    }
2121                                    catch (NoSuchImageException nsie) {
2122                                            continue;
2123                                    }
2124    
2125                                    imageId = journalArticleImageLocalService.getArticleImageId(
2126                                            newArticle.getGroupId(), newArticle.getArticleId(),
2127                                            newArticle.getVersion(), instanceId, name, languageId);
2128    
2129                                    imageLocalService.updateImage(imageId, oldImage.getTextObj());
2130    
2131                                    String elContent =
2132                                            "/image/journal/article?img_id=" + imageId + "&t=" +
2133                                                    ImageServletTokenUtil.getToken(imageId);
2134    
2135                                    dynamicContentEl.setText(elContent);
2136                                    dynamicContentEl.addAttribute("id", String.valueOf(imageId));
2137                            }
2138                    }
2139    
2140                    newArticle.setContent(contentDoc.formattedString());
2141            }
2142    
2143            protected void format(
2144                            long groupId, String articleId, double version,
2145                            boolean incrementVersion, Element root, Map<String, byte[]> images)
2146                    throws PortalException, SystemException {
2147    
2148                    for (Element el : root.elements()) {
2149                            String elInstanceId = el.attributeValue(
2150                                    "instance-id", StringPool.BLANK);
2151                            String elName = el.attributeValue("name", StringPool.BLANK);
2152                            String elType = el.attributeValue("type", StringPool.BLANK);
2153    
2154                            if (elType.equals("image")) {
2155                                    formatImage(
2156                                            groupId, articleId, version, incrementVersion, el,
2157                                            elInstanceId, elName, images);
2158                            }
2159                            /*else if (elType.equals("text_area")) {
2160                                    Element dynamicContent = el.element("dynamic-content");
2161    
2162                                    String text = dynamicContent.getText();
2163    
2164                                    // LEP-1594
2165    
2166                                    try {
2167                                            text = ParserUtils.trimTags(
2168                                                    text, new String[] {"script"}, false, true);
2169                                    }
2170                                    catch (ParserException pe) {
2171                                            text = pe.getLocalizedMessage();
2172                                    }
2173                                    catch (UnsupportedEncodingException uee) {
2174                                            text = uee.getLocalizedMessage();
2175                                    }
2176    
2177                                    dynamicContent.setText(text);
2178                            }*/
2179    
2180                            format(groupId, articleId, version, incrementVersion, el, images);
2181                    }
2182            }
2183    
2184            protected String format(
2185                            long groupId, String articleId, double version,
2186                            boolean incrementVersion, String content, String structureId,
2187                            Map<String, byte[]> images)
2188                    throws PortalException, SystemException {
2189    
2190                    if (Validator.isNotNull(structureId)) {
2191                            Document doc = null;
2192    
2193                            try {
2194                                    doc = SAXReaderUtil.read(content);
2195    
2196                                    Element root = doc.getRootElement();
2197    
2198                                    format(
2199                                            groupId, articleId, version, incrementVersion, root,
2200                                            images);
2201    
2202                                    content = JournalUtil.formatXML(doc);
2203                            }
2204                            catch (DocumentException de) {
2205                                    _log.error(de);
2206                            }
2207                            catch (IOException ioe) {
2208                                    _log.error(ioe);
2209                            }
2210                    }
2211    
2212                    content = HtmlUtil.replaceMsWordCharacters(content);
2213    
2214                    return content;
2215            }
2216    
2217            protected void formatImage(
2218                            long groupId, String articleId, double version,
2219                            boolean incrementVersion, Element el, String elInstanceId,
2220                            String elName, Map<String, byte[]> images)
2221                    throws PortalException, SystemException {
2222    
2223                    List<Element> imageContents = el.elements("dynamic-content");
2224    
2225                    for (Element dynamicContent : imageContents) {
2226                            String elLanguage = dynamicContent.attributeValue(
2227                                    "language-id", StringPool.BLANK);
2228    
2229                            if (!elLanguage.equals(StringPool.BLANK)) {
2230                                    elLanguage = "_" + elLanguage;
2231                            }
2232    
2233                            long imageId =
2234                                    journalArticleImageLocalService.getArticleImageId(
2235                                            groupId, articleId, version, elInstanceId, elName,
2236                                            elLanguage);
2237    
2238                            double oldVersion = MathUtil.format(version - 0.1, 1, 1);
2239    
2240                            long oldImageId = 0;
2241    
2242                            if ((oldVersion >= 1) && incrementVersion) {
2243                                    oldImageId =
2244                                            journalArticleImageLocalService.getArticleImageId(
2245                                                    groupId, articleId, oldVersion, elInstanceId, elName,
2246                                                    elLanguage);
2247                            }
2248    
2249                            String elContent =
2250                                    "/image/journal/article?img_id=" + imageId + "&t=" +
2251                                            ImageServletTokenUtil.getToken(imageId);
2252    
2253                            if (dynamicContent.getText().equals("delete")) {
2254                                    dynamicContent.setText(StringPool.BLANK);
2255    
2256                                    imageLocalService.deleteImage(imageId);
2257    
2258                                    String defaultElLanguage = "";
2259    
2260                                    if (!Validator.isNotNull(elLanguage)) {
2261                                            defaultElLanguage =
2262                                                    "_" + LocaleUtil.toLanguageId(LocaleUtil.getDefault());
2263                                    }
2264    
2265                                    long defaultImageId =
2266                                            journalArticleImageLocalService.getArticleImageId(
2267                                                    groupId, articleId, version, elInstanceId, elName,
2268                                                    defaultElLanguage);
2269    
2270                                    imageLocalService.deleteImage(defaultImageId);
2271    
2272                                    continue;
2273                            }
2274    
2275                            byte[] bytes = images.get(elInstanceId + "_" + elName + elLanguage);
2276    
2277                            if (bytes != null && (bytes.length > 0)) {
2278                                    dynamicContent.setText(elContent);
2279                                    dynamicContent.addAttribute("id", String.valueOf(imageId));
2280    
2281                                    imageLocalService.updateImage(imageId, bytes);
2282    
2283                                    continue;
2284                            }
2285    
2286                            if ((version > JournalArticleConstants.DEFAULT_VERSION) &&
2287                                    (incrementVersion)) {
2288    
2289                                    Image oldImage = null;
2290    
2291                                    if (oldImageId > 0) {
2292                                            oldImage = imageLocalService.getImage(oldImageId);
2293                                    }
2294    
2295                                    if (oldImage != null) {
2296                                            dynamicContent.setText(elContent);
2297                                            dynamicContent.addAttribute("id", String.valueOf(imageId));
2298    
2299                                            bytes = oldImage.getTextObj();
2300    
2301                                            imageLocalService.updateImage(imageId, bytes);
2302                                    }
2303    
2304                                    continue;
2305                            }
2306    
2307                            Image image = imageLocalService.getImage(imageId);
2308    
2309                            if (image != null) {
2310                                    dynamicContent.setText(elContent);
2311                                    dynamicContent.addAttribute("id", String.valueOf(imageId));
2312    
2313                                    continue;
2314                            }
2315    
2316                            long contentImageId = GetterUtil.getLong(HttpUtil.getParameter(
2317                                    dynamicContent.getText(), "img_id"));
2318    
2319                            if (contentImageId <= 0) {
2320                                    contentImageId = GetterUtil.getLong(HttpUtil.getParameter(
2321                                            dynamicContent.getText(), "img_id", false));
2322                            }
2323    
2324                            if (contentImageId > 0) {
2325                                    image = imageLocalService.getImage(contentImageId);
2326    
2327                                    if (image != null) {
2328                                            dynamicContent.addAttribute(
2329                                                    "id", String.valueOf(contentImageId));
2330    
2331                                            continue;
2332                                    }
2333                            }
2334    
2335                            String defaultElLanguage = "";
2336    
2337                            if (!Validator.isNotNull(elLanguage)) {
2338                                    defaultElLanguage =
2339                                            "_" + LocaleUtil.toLanguageId(LocaleUtil.getDefault());
2340                            }
2341    
2342                            long defaultImageId =
2343                                    journalArticleImageLocalService.getArticleImageId(
2344                                            groupId, articleId, version, elInstanceId, elName,
2345                                            defaultElLanguage);
2346    
2347                            Image defaultImage = imageLocalService.getImage(defaultImageId);
2348    
2349                            if (defaultImage != null) {
2350                                    dynamicContent.setText(elContent);
2351                                    dynamicContent.addAttribute(
2352                                            "id", String.valueOf(defaultImageId));
2353    
2354                                    bytes = defaultImage.getTextObj();
2355    
2356                                    imageLocalService.updateImage(defaultImageId, bytes);
2357    
2358                                    continue;
2359                            }
2360    
2361                            dynamicContent.setText(StringPool.BLANK);
2362                    }
2363            }
2364    
2365            protected Date[] getDateInterval(
2366                            long groupId, String articleId, Date earliestDisplayDate,
2367                            Date latestExpirationDate)
2368                    throws SystemException {
2369    
2370                    Date[] dateInterval = new Date[2];
2371    
2372                    List<JournalArticle> articles = journalArticlePersistence.findByG_A_ST(
2373                            groupId, articleId, WorkflowConstants.STATUS_APPROVED);
2374    
2375                    boolean expiringArticle = true;
2376    
2377                    if (latestExpirationDate == null) {
2378                            expiringArticle = false;
2379                    }
2380    
2381                    for (JournalArticle article : articles) {
2382                            if ((earliestDisplayDate == null) ||
2383                                    ((article.getDisplayDate() != null) &&
2384                                     earliestDisplayDate.after(article.getDisplayDate()))) {
2385    
2386                                    earliestDisplayDate = article.getDisplayDate();
2387                            }
2388    
2389                            if (expiringArticle &&
2390                                    ((latestExpirationDate == null) ||
2391                                     ((article.getExpirationDate() != null) &&
2392                                      latestExpirationDate.before(article.getExpirationDate())))) {
2393    
2394                                    latestExpirationDate = article.getExpirationDate();
2395                            }
2396    
2397                            if (expiringArticle && (article.getExpirationDate() == null)) {
2398                                    latestExpirationDate = null;
2399                                    expiringArticle = false;
2400                            }
2401                    }
2402    
2403                    dateInterval[0] = earliestDisplayDate;
2404                    dateInterval[1] = latestExpirationDate;
2405    
2406                    return dateInterval;
2407            }
2408    
2409            protected String getUniqueUrlTitle(
2410                            long id, long groupId, String articleId, String title)
2411                    throws PortalException, SystemException {
2412    
2413                    String urlTitle = JournalUtil.getUrlTitle(id, title);
2414    
2415                    String newUrlTitle = urlTitle;
2416    
2417                    for (int i = 1;; i++) {
2418                            JournalArticle article = null;
2419    
2420                            try {
2421                                    article = getArticleByUrlTitle(groupId, newUrlTitle);
2422                            }
2423                            catch (NoSuchArticleException nsae) {
2424                            }
2425    
2426                            if ((article == null) || article.getArticleId().equals(articleId)) {
2427                                    break;
2428                            }
2429                            else {
2430                                    newUrlTitle = urlTitle + StringPool.DASH + i;
2431                            }
2432                    }
2433    
2434                    return newUrlTitle;
2435            }
2436    
2437            protected void notifySubscribers(
2438                            JournalArticle article, ServiceContext serviceContext)
2439                    throws PortalException, SystemException {
2440    
2441                    if (!article.isApproved()) {
2442                            return;
2443                    }
2444    
2445                    String articleURL = PortalUtil.getControlPanelFullURL(
2446                            serviceContext.getScopeGroupId(), PortletKeys.JOURNAL, null);
2447    
2448                    if (Validator.isNull(articleURL)) {
2449                            return;
2450                    }
2451    
2452                    PortletPreferences preferences =
2453                            ServiceContextUtil.getPortletPreferences(serviceContext);
2454    
2455                    if (preferences == null) {
2456                            long ownerId = article.getGroupId();
2457                            int ownerType = PortletKeys.PREFS_OWNER_TYPE_GROUP;
2458                            long plid = PortletKeys.PREFS_PLID_SHARED;
2459                            String portletId = PortletKeys.JOURNAL;
2460                            String defaultPreferences = null;
2461    
2462                            preferences = portletPreferencesLocalService.getPreferences(
2463                                    article.getCompanyId(), ownerId, ownerType, plid, portletId,
2464                                    defaultPreferences);
2465                    }
2466    
2467                    if ((article.getVersion() == 1.0) &&
2468                            JournalUtil.getEmailArticleAddedEnabled(preferences)) {
2469                    }
2470                    else if ((article.getVersion() != 1.0) &&
2471                                     JournalUtil.getEmailArticleUpdatedEnabled(preferences)) {
2472                    }
2473                    else {
2474                            return;
2475                    }
2476    
2477                    Company company = companyPersistence.findByPrimaryKey(
2478                            article.getCompanyId());
2479    
2480                    String emailAddress = StringPool.BLANK;
2481                    String fullName = article.getUserName();
2482    
2483                    try {
2484                            User user = userPersistence.findByPrimaryKey(article.getUserId());
2485    
2486                            emailAddress = user.getEmailAddress();
2487                            fullName = user.getFullName();
2488                    }
2489                    catch (NoSuchUserException nsue) {
2490                    }
2491    
2492                    String portletName = PortalUtil.getPortletTitle(
2493                            PortletKeys.JOURNAL, LocaleUtil.getDefault());
2494    
2495                    String fromName = JournalUtil.getEmailFromName(preferences);
2496                    String fromAddress = JournalUtil.getEmailFromAddress(preferences);
2497    
2498                    fromName = StringUtil.replace(
2499                            fromName,
2500                            new String[] {
2501                                    "[$ARTICLE_ID$]",
2502                                    "[$ARTICLE_TITLE$]",
2503                                    "[$ARTICLE_USER_ADDRESS$]",
2504                                    "[$ARTICLE_USER_NAME$]",
2505                                    "[$ARTICLE_VERSION$]",
2506                                    "[$FROM_ADDRESS$]",
2507                                    "[$FROM_NAME$]",
2508                                    "[$PORTAL_URL$]",
2509                                    "[$PORTLET_NAME$]",
2510                            },
2511                            new String[] {
2512                                    article.getArticleId(),
2513                                    article.getTitle(),
2514                                    emailAddress,
2515                                    fullName,
2516                                    String.valueOf(article.getVersion()),
2517                                    fromAddress,
2518                                    fromName,
2519                                    company.getVirtualHost(),
2520                                    portletName,
2521                            });
2522    
2523                    fromAddress = StringUtil.replace(
2524                            fromAddress,
2525                            new String[] {
2526                                    "[$ARTICLE_ID$]",
2527                                    "[$ARTICLE_TITLE$]",
2528                                    "[$ARTICLE_USER_ADDRESS$]",
2529                                    "[$ARTICLE_USER_NAME$]",
2530                                    "[$ARTICLE_VERSION$]",
2531                                    "[$FROM_ADDRESS$]",
2532                                    "[$FROM_NAME$]",
2533                                    "[$PORTAL_URL$]",
2534                                    "[$PORTLET_NAME$]",
2535                            },
2536                            new String[] {
2537                                    article.getArticleId(),
2538                                    article.getTitle(),
2539                                    emailAddress,
2540                                    fullName,
2541                                    String.valueOf(article.getVersion()),
2542                                    fromAddress,
2543                                    fromName,
2544                                    company.getVirtualHost(),
2545                                    portletName,
2546                            });
2547    
2548                    String subject = null;
2549                    String body = null;
2550    
2551                    if (article.getVersion() == 1.0) {
2552                            subject = JournalUtil.getEmailArticleAddedSubject(preferences);
2553                            body = JournalUtil.getEmailArticleAddedBody(preferences);
2554                    }
2555                    else {
2556                            subject = JournalUtil.getEmailArticleUpdatedSubject(preferences);
2557                            body = JournalUtil.getEmailArticleUpdatedBody(preferences);
2558                    }
2559    
2560                    subject = StringUtil.replace(
2561                            subject,
2562                            new String[] {
2563                                    "[$ARTICLE_ID$]",
2564                                    "[$ARTICLE_TITLE$]",
2565                                    "[$ARTICLE_URL$]",
2566                                    "[$ARTICLE_USER_ADDRESS$]",
2567                                    "[$ARTICLE_USER_NAME$]",
2568                                    "[$ARTICLE_VERSION$]",
2569                                    "[$FROM_ADDRESS$]",
2570                                    "[$FROM_NAME$]",
2571                                    "[$PORTAL_URL$]",
2572                                    "[$PORTLET_NAME$]",
2573                            },
2574                            new String[] {
2575                                    article.getArticleId(),
2576                                    article.getTitle(),
2577                                    articleURL,
2578                                    emailAddress,
2579                                    fullName,
2580                                    String.valueOf(article.getVersion()),
2581                                    fromAddress,
2582                                    fromName,
2583                                    company.getVirtualHost(),
2584                                    portletName,
2585                            });
2586    
2587                    body = StringUtil.replace(
2588                            body,
2589                            new String[] {
2590                                    "[$ARTICLE_ID$]",
2591                                    "[$ARTICLE_TITLE$]",
2592                                    "[$ARTICLE_URL$]",
2593                                    "[$ARTICLE_USER_ADDRESS$]",
2594                                    "[$ARTICLE_USER_NAME$]",
2595                                    "[$ARTICLE_VERSION$]",
2596                                    "[$FROM_ADDRESS$]",
2597                                    "[$FROM_NAME$]",
2598                                    "[$PORTAL_URL$]",
2599                                    "[$PORTLET_NAME$]",
2600                            },
2601                            new String[] {
2602                                    article.getArticleId(),
2603                                    article.getTitle(),
2604                                    articleURL,
2605                                    emailAddress,
2606                                    fullName,
2607                                    String.valueOf(article.getVersion()),
2608                                    fromAddress,
2609                                    fromName,
2610                                    company.getVirtualHost(),
2611                                    portletName,
2612                            });
2613    
2614                    Message message = new Message();
2615    
2616                    message.put("companyId", article.getCompanyId());
2617                    message.put("userId", article.getUserId());
2618                    message.put("groupId", article.getGroupId());
2619                    message.put("articleId", article.getArticleId());
2620                    message.put("fromName", fromName);
2621                    message.put("fromAddress", fromAddress);
2622                    message.put("subject", subject);
2623                    message.put("body", body);
2624                    message.put("replyToAddress", fromAddress);
2625                    message.put(
2626                            "mailId",
2627                            JournalUtil.getMailId(company.getMx(), article.getArticleId()));
2628                    message.put("htmlFormat", Boolean.TRUE);
2629    
2630                    MessageBusUtil.sendMessage(DestinationNames.JOURNAL, message);
2631            }
2632    
2633            protected void saveImages(
2634                            boolean smallImage, long smallImageId, File smallFile,
2635                            byte[] smallBytes)
2636                    throws PortalException, SystemException {
2637    
2638                    if (smallImage) {
2639                            if ((smallFile != null) && (smallBytes != null)) {
2640                                    imageLocalService.updateImage(smallImageId, smallBytes);
2641                            }
2642                    }
2643                    else {
2644                            imageLocalService.deleteImage(smallImageId);
2645                    }
2646            }
2647    
2648            protected void sendEmail(
2649                            JournalArticle article, String articleURL,
2650                            PortletPreferences preferences, String emailType)
2651                    throws IOException, PortalException, SystemException {
2652    
2653                    if (preferences == null) {
2654                            return;
2655                    }
2656                    else if (emailType.equals("denied") &&
2657                            JournalUtil.getEmailArticleApprovalDeniedEnabled(preferences)) {
2658                    }
2659                    else if (emailType.equals("granted") &&
2660                                     JournalUtil.getEmailArticleApprovalGrantedEnabled(
2661                                            preferences)) {
2662                    }
2663                    else if (emailType.equals("requested") &&
2664                                     JournalUtil.getEmailArticleApprovalRequestedEnabled(
2665                                            preferences)) {
2666                    }
2667                    else if (emailType.equals("review") &&
2668                                     JournalUtil.getEmailArticleReviewEnabled(preferences)) {
2669                    }
2670                    else {
2671                            return;
2672                    }
2673    
2674                    Company company = companyPersistence.findByPrimaryKey(
2675                            article.getCompanyId());
2676    
2677                    User user = userPersistence.findByPrimaryKey(article.getUserId());
2678    
2679                    articleURL +=
2680                            "&groupId=" + article.getGroupId() + "&articleId=" +
2681                                    article.getArticleId() + "&version=" + article.getVersion();
2682    
2683                    String portletName = PortalUtil.getPortletTitle(
2684                            PortletKeys.JOURNAL, user);
2685    
2686                    String fromName = JournalUtil.getEmailFromName(preferences);
2687                    String fromAddress = JournalUtil.getEmailFromAddress(preferences);
2688    
2689                    String toName = user.getFullName();
2690                    String toAddress = user.getEmailAddress();
2691    
2692                    if (emailType.equals("requested") ||
2693                            emailType.equals("review")) {
2694    
2695                            String tempToName = fromName;
2696                            String tempToAddress = fromAddress;
2697    
2698                            fromName = toName;
2699                            fromAddress = toAddress;
2700    
2701                            toName = tempToName;
2702                            toAddress = tempToAddress;
2703                    }
2704    
2705                    String subject = null;
2706                    String body = null;
2707    
2708                    if (emailType.equals("denied")) {
2709                            subject =
2710                                    JournalUtil.getEmailArticleApprovalDeniedSubject(preferences);
2711                            body = JournalUtil.getEmailArticleApprovalDeniedBody(preferences);
2712                    }
2713                    else if (emailType.equals("granted")) {
2714                            subject =
2715                                    JournalUtil.getEmailArticleApprovalGrantedSubject(preferences);
2716                            body = JournalUtil.getEmailArticleApprovalGrantedBody(preferences);
2717                    }
2718                    else if (emailType.equals("requested")) {
2719                            subject =
2720                                    JournalUtil.getEmailArticleApprovalRequestedSubject(
2721                                    preferences);
2722                            body = JournalUtil.getEmailArticleApprovalRequestedBody(
2723                                    preferences);
2724                    }
2725                    else if (emailType.equals("review")) {
2726                            subject = JournalUtil.getEmailArticleReviewSubject(preferences);
2727                            body = JournalUtil.getEmailArticleReviewBody(preferences);
2728                    }
2729    
2730                    subject = StringUtil.replace(
2731                            subject,
2732                            new String[] {
2733                                    "[$ARTICLE_ID$]",
2734                                    "[$ARTICLE_TITLE$]",
2735                                    "[$ARTICLE_URL$]",
2736                                    "[$ARTICLE_USER_NAME$]",
2737                                    "[$ARTICLE_VERSION$]",
2738                                    "[$FROM_ADDRESS$]",
2739                                    "[$FROM_NAME$]",
2740                                    "[$PORTAL_URL$]",
2741                                    "[$PORTLET_NAME$]",
2742                                    "[$TO_ADDRESS$]",
2743                                    "[$TO_NAME$]"
2744                            },
2745                            new String[] {
2746                                    article.getArticleId(),
2747                                    article.getTitle(),
2748                                    articleURL,
2749                                    article.getUserName(),
2750                                    String.valueOf(article.getVersion()),
2751                                    fromAddress,
2752                                    fromName,
2753                                    company.getVirtualHost(),
2754                                    portletName,
2755                                    toAddress,
2756                                    toName,
2757                            });
2758    
2759                    body = StringUtil.replace(
2760                            body,
2761                            new String[] {
2762                                    "[$ARTICLE_ID$]",
2763                                    "[$ARTICLE_TITLE$]",
2764                                    "[$ARTICLE_URL$]",
2765                                    "[$ARTICLE_USER_NAME$]",
2766                                    "[$ARTICLE_VERSION$]",
2767                                    "[$FROM_ADDRESS$]",
2768                                    "[$FROM_NAME$]",
2769                                    "[$PORTAL_URL$]",
2770                                    "[$PORTLET_NAME$]",
2771                                    "[$TO_ADDRESS$]",
2772                                    "[$TO_NAME$]"
2773                            },
2774                            new String[] {
2775                                    article.getArticleId(),
2776                                    article.getTitle(),
2777                                    articleURL,
2778                                    article.getUserName(),
2779                                    String.valueOf(article.getVersion()),
2780                                    fromAddress,
2781                                    fromName,
2782                                    company.getVirtualHost(),
2783                                    portletName,
2784                                    toAddress,
2785                                    toName,
2786                            });
2787    
2788                    InternetAddress from = new InternetAddress(fromAddress, fromName);
2789    
2790                    InternetAddress to = new InternetAddress(toAddress, toName);
2791    
2792                    MailMessage message = new MailMessage(from, to, subject, body, true);
2793    
2794                    mailService.sendEmail(message);
2795            }
2796    
2797            protected void updatePreviousApprovedArticle(JournalArticle article)
2798                    throws PortalException, SystemException {
2799    
2800                    List<JournalArticle> approvedArticles =
2801                            journalArticlePersistence.findByG_A_ST(
2802                                    article.getGroupId(), article.getArticleId(),
2803                                    WorkflowConstants.STATUS_APPROVED, 0, 2);
2804    
2805                    if (approvedArticles.size() > 1) {
2806                            JournalArticle previousApprovedArticle = approvedArticles.get(1);
2807    
2808                            if (article.isIndexable()) {
2809                                    Indexer indexer = IndexerRegistryUtil.getIndexer(
2810                                            JournalArticle.class);
2811    
2812                                    indexer.reindex(previousApprovedArticle);
2813                            }
2814                    }
2815                    else {
2816                            if (article.isIndexable()) {
2817                                    Indexer indexer = IndexerRegistryUtil.getIndexer(
2818                                            JournalArticle.class);
2819    
2820                                    indexer.delete(article);
2821                            }
2822    
2823                            assetEntryLocalService.updateVisible(
2824                                    JournalArticle.class.getName(), article.getResourcePrimKey(),
2825                                    false);
2826                    }
2827            }
2828    
2829            protected void updateUrlTitles(
2830                            long groupId, String articleId, String urlTitle)
2831                    throws SystemException {
2832    
2833                    List<JournalArticle> articles = journalArticlePersistence.findByG_A(
2834                            groupId, articleId);
2835    
2836                    for (JournalArticle article : articles) {
2837                            if (!article.getUrlTitle().equals(urlTitle)) {
2838                                    article.setUrlTitle(urlTitle);
2839    
2840                                    journalArticlePersistence.update(article, false);
2841                            }
2842                    }
2843            }
2844    
2845            protected void validate(
2846                            long groupId, String articleId, boolean autoArticleId,
2847                            double version, String title, String content, String type,
2848                            String structureId, String templateId, boolean smallImage,
2849                            String smallImageURL, File smallFile, byte[] smallBytes)
2850                    throws PortalException, SystemException {
2851    
2852                    if (!autoArticleId) {
2853                            validate(articleId);
2854    
2855                            JournalArticle article = journalArticlePersistence.fetchByG_A_V(
2856                                    groupId, articleId, version);
2857    
2858                            if (article != null) {
2859                                    throw new DuplicateArticleIdException();
2860                            }
2861                    }
2862    
2863                    validate(
2864                            groupId, title, content, type, structureId, templateId,
2865                            smallImage, smallImageURL, smallFile, smallBytes);
2866            }
2867    
2868            protected void validate(
2869                            long groupId, String title, String content, String type,
2870                            String structureId, String templateId, boolean smallImage,
2871                            String smallImageURL, File smallFile, byte[] smallBytes)
2872                    throws PortalException, SystemException {
2873    
2874                    if (Validator.isNull(title)) {
2875                            throw new ArticleTitleException();
2876                    }
2877                    else if (Validator.isNull(content)) {
2878                            throw new ArticleContentException();
2879                    }
2880                    else if (Validator.isNull(type)) {
2881                            throw new ArticleTypeException();
2882                    }
2883    
2884                    if (Validator.isNotNull(structureId)) {
2885                            journalStructurePersistence.findByG_S(groupId, structureId);
2886    
2887                            JournalTemplate template = journalTemplatePersistence.findByG_T(
2888                                    groupId, templateId);
2889    
2890                            if (!template.getStructureId().equals(structureId)) {
2891                                    throw new NoSuchTemplateException();
2892                            }
2893                    }
2894    
2895                    String[] imageExtensions = PrefsPropsUtil.getStringArray(
2896                            PropsKeys.JOURNAL_IMAGE_EXTENSIONS, StringPool.COMMA);
2897    
2898                    if (smallImage && Validator.isNull(smallImageURL) &&
2899                            smallFile != null && smallBytes != null) {
2900    
2901                            String smallImageName = smallFile.getName();
2902    
2903                            if (smallImageName != null) {
2904                                    boolean validSmallImageExtension = false;
2905    
2906                                    for (String _imageExtension : imageExtensions) {
2907                                            if (StringPool.STAR.equals(_imageExtension) ||
2908                                                    StringUtil.endsWith(smallImageName, _imageExtension)) {
2909    
2910                                                    validSmallImageExtension = true;
2911    
2912                                                    break;
2913                                            }
2914                                    }
2915    
2916                                    if (!validSmallImageExtension) {
2917                                            throw new ArticleSmallImageNameException(smallImageName);
2918                                    }
2919                            }
2920    
2921                            long smallImageMaxSize = PrefsPropsUtil.getLong(
2922                                    PropsKeys.JOURNAL_IMAGE_SMALL_MAX_SIZE);
2923    
2924                            if ((smallImageMaxSize > 0) &&
2925                                    ((smallBytes == null) ||
2926                                            (smallBytes.length > smallImageMaxSize))) {
2927    
2928                                    throw new ArticleSmallImageSizeException();
2929                            }
2930                    }
2931            }
2932    
2933            protected void validate(String articleId) throws PortalException {
2934                    if ((Validator.isNull(articleId)) ||
2935                            (articleId.indexOf(StringPool.SPACE) != -1)) {
2936    
2937                            throw new ArticleIdException();
2938                    }
2939            }
2940    
2941            private static final String _TOKEN_PAGE_BREAK = PropsUtil.get(
2942                    PropsKeys.JOURNAL_ARTICLE_TOKEN_PAGE_BREAK);
2943    
2944            private long _journalArticleCheckInterval =
2945                    PropsValues.JOURNAL_ARTICLE_CHECK_INTERVAL * Time.MINUTE;
2946    
2947            private static Log _log = LogFactoryUtil.getLog(
2948                    JournalArticleLocalServiceImpl.class);
2949    
2950    }