001    /**
002     * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
013     */
014    
015    package com.liferay.portlet.journal.service.impl;
016    
017    import com.liferay.portal.LocaleException;
018    import com.liferay.portal.NoSuchImageException;
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.language.LanguageUtil;
023    import com.liferay.portal.kernel.log.Log;
024    import com.liferay.portal.kernel.log.LogFactoryUtil;
025    import com.liferay.portal.kernel.sanitizer.SanitizerUtil;
026    import com.liferay.portal.kernel.search.Field;
027    import com.liferay.portal.kernel.search.Hits;
028    import com.liferay.portal.kernel.search.Indexer;
029    import com.liferay.portal.kernel.search.IndexerRegistryUtil;
030    import com.liferay.portal.kernel.search.QueryConfig;
031    import com.liferay.portal.kernel.search.SearchContext;
032    import com.liferay.portal.kernel.search.Sort;
033    import com.liferay.portal.kernel.util.ArrayUtil;
034    import com.liferay.portal.kernel.util.CalendarFactoryUtil;
035    import com.liferay.portal.kernel.util.CharPool;
036    import com.liferay.portal.kernel.util.ContentTypes;
037    import com.liferay.portal.kernel.util.FileUtil;
038    import com.liferay.portal.kernel.util.GetterUtil;
039    import com.liferay.portal.kernel.util.HtmlUtil;
040    import com.liferay.portal.kernel.util.HttpUtil;
041    import com.liferay.portal.kernel.util.ListUtil;
042    import com.liferay.portal.kernel.util.LocaleUtil;
043    import com.liferay.portal.kernel.util.LocalizationUtil;
044    import com.liferay.portal.kernel.util.MathUtil;
045    import com.liferay.portal.kernel.util.OrderByComparator;
046    import com.liferay.portal.kernel.util.ParamUtil;
047    import com.liferay.portal.kernel.util.PropsKeys;
048    import com.liferay.portal.kernel.util.StringPool;
049    import com.liferay.portal.kernel.util.StringUtil;
050    import com.liferay.portal.kernel.util.Time;
051    import com.liferay.portal.kernel.util.Validator;
052    import com.liferay.portal.kernel.workflow.WorkflowConstants;
053    import com.liferay.portal.kernel.workflow.WorkflowHandlerRegistryUtil;
054    import com.liferay.portal.kernel.xml.Document;
055    import com.liferay.portal.kernel.xml.DocumentException;
056    import com.liferay.portal.kernel.xml.Element;
057    import com.liferay.portal.kernel.xml.Node;
058    import com.liferay.portal.kernel.xml.SAXReaderUtil;
059    import com.liferay.portal.kernel.xml.XPath;
060    import com.liferay.portal.model.Company;
061    import com.liferay.portal.model.Group;
062    import com.liferay.portal.model.Image;
063    import com.liferay.portal.model.ResourceConstants;
064    import com.liferay.portal.model.User;
065    import com.liferay.portal.service.ServiceContext;
066    import com.liferay.portal.service.ServiceContextUtil;
067    import com.liferay.portal.servlet.filters.cache.CacheUtil;
068    import com.liferay.portal.theme.ThemeDisplay;
069    import com.liferay.portal.util.PortalUtil;
070    import com.liferay.portal.util.PortletKeys;
071    import com.liferay.portal.util.PrefsPropsUtil;
072    import com.liferay.portal.util.PropsValues;
073    import com.liferay.portal.util.SubscriptionSender;
074    import com.liferay.portal.webserver.WebServerServletTokenUtil;
075    import com.liferay.portlet.asset.NoSuchEntryException;
076    import com.liferay.portlet.asset.model.AssetEntry;
077    import com.liferay.portlet.asset.model.AssetLink;
078    import com.liferay.portlet.asset.model.AssetLinkConstants;
079    import com.liferay.portlet.dynamicdatamapping.util.DDMXMLUtil;
080    import com.liferay.portlet.expando.model.ExpandoBridge;
081    import com.liferay.portlet.journal.ArticleContentException;
082    import com.liferay.portlet.journal.ArticleDisplayDateException;
083    import com.liferay.portlet.journal.ArticleExpirationDateException;
084    import com.liferay.portlet.journal.ArticleIdException;
085    import com.liferay.portlet.journal.ArticleReviewDateException;
086    import com.liferay.portlet.journal.ArticleSmallImageNameException;
087    import com.liferay.portlet.journal.ArticleSmallImageSizeException;
088    import com.liferay.portlet.journal.ArticleTitleException;
089    import com.liferay.portlet.journal.ArticleTypeException;
090    import com.liferay.portlet.journal.ArticleVersionException;
091    import com.liferay.portlet.journal.DuplicateArticleIdException;
092    import com.liferay.portlet.journal.NoSuchArticleException;
093    import com.liferay.portlet.journal.NoSuchArticleResourceException;
094    import com.liferay.portlet.journal.NoSuchStructureException;
095    import com.liferay.portlet.journal.NoSuchTemplateException;
096    import com.liferay.portlet.journal.StructureXsdException;
097    import com.liferay.portlet.journal.model.JournalArticle;
098    import com.liferay.portlet.journal.model.JournalArticleConstants;
099    import com.liferay.portlet.journal.model.JournalArticleDisplay;
100    import com.liferay.portlet.journal.model.JournalArticleResource;
101    import com.liferay.portlet.journal.model.JournalStructure;
102    import com.liferay.portlet.journal.model.JournalTemplate;
103    import com.liferay.portlet.journal.model.impl.JournalArticleDisplayImpl;
104    import com.liferay.portlet.journal.service.base.JournalArticleLocalServiceBaseImpl;
105    import com.liferay.portlet.journal.util.JournalUtil;
106    import com.liferay.portlet.journal.util.comparator.ArticleIDComparator;
107    import com.liferay.portlet.journal.util.comparator.ArticleVersionComparator;
108    import com.liferay.portlet.journalcontent.util.JournalContentUtil;
109    
110    import java.io.File;
111    import java.io.IOException;
112    import java.io.Serializable;
113    
114    import java.util.Calendar;
115    import java.util.Date;
116    import java.util.HashMap;
117    import java.util.HashSet;
118    import java.util.LinkedHashMap;
119    import java.util.List;
120    import java.util.Locale;
121    import java.util.Map;
122    import java.util.Set;
123    import java.util.regex.Matcher;
124    import java.util.regex.Pattern;
125    
126    import javax.portlet.PortletPreferences;
127    
128    /**
129     * @author Brian Wing Shun Chan
130     * @author Raymond Augé
131     * @author Bruno Farache
132     * @author Juan Fernández
133     */
134    public class JournalArticleLocalServiceImpl
135            extends JournalArticleLocalServiceBaseImpl {
136    
137            public JournalArticle addArticle(
138                            long userId, long groupId, long classNameId, long classPK,
139                            String articleId, boolean autoArticleId, double version,
140                            Map<Locale, String> titleMap, Map<Locale, String> descriptionMap,
141                            String content, String type, String structureId, String templateId,
142                            String layoutUuid, int displayDateMonth, int displayDateDay,
143                            int displayDateYear, int displayDateHour, int displayDateMinute,
144                            int expirationDateMonth, int expirationDateDay,
145                            int expirationDateYear, int expirationDateHour,
146                            int expirationDateMinute, boolean neverExpire, int reviewDateMonth,
147                            int reviewDateDay, int reviewDateYear, int reviewDateHour,
148                            int reviewDateMinute, boolean neverReview, boolean indexable,
149                            boolean smallImage, String smallImageURL, File smallImageFile,
150                            Map<String, byte[]> images, String articleURL,
151                            ServiceContext serviceContext)
152                    throws PortalException, SystemException {
153    
154                    // Article
155    
156                    User user = userPersistence.findByPrimaryKey(userId);
157                    articleId = articleId.trim().toUpperCase();
158    
159                    Date displayDate = PortalUtil.getDate(
160                            displayDateMonth, displayDateDay, displayDateYear, displayDateHour,
161                            displayDateMinute, user.getTimeZone(),
162                            ArticleDisplayDateException.class);
163    
164                    Date expirationDate = null;
165    
166                    if (!neverExpire) {
167                            expirationDate = PortalUtil.getDate(
168                                    expirationDateMonth, expirationDateDay, expirationDateYear,
169                                    expirationDateHour, expirationDateMinute, user.getTimeZone(),
170                                    ArticleExpirationDateException.class);
171                    }
172    
173                    Date reviewDate = null;
174    
175                    if (!neverReview) {
176                            reviewDate = PortalUtil.getDate(
177                                    reviewDateMonth, reviewDateDay, reviewDateYear, reviewDateHour,
178                                    reviewDateMinute, user.getTimeZone(),
179                                    ArticleReviewDateException.class);
180                    }
181    
182                    byte[] smallImageBytes = null;
183    
184                    try {
185                            smallImageBytes = FileUtil.getBytes(smallImageFile);
186                    }
187                    catch (IOException ioe) {
188                    }
189    
190                    Date now = new Date();
191    
192                    validate(
193                            user.getCompanyId(), groupId, classNameId, articleId, autoArticleId,
194                            version, titleMap, content, type, structureId, templateId,
195                            smallImage, smallImageURL, smallImageFile, smallImageBytes);
196    
197                    if (autoArticleId) {
198                            articleId = String.valueOf(counterLocalService.increment());
199                    }
200    
201                    long id = counterLocalService.increment();
202    
203                    long resourcePrimKey =
204                            journalArticleResourceLocalService.getArticleResourcePrimKey(
205                                    serviceContext.getUuid(), groupId, articleId);
206    
207                    JournalArticle article = journalArticlePersistence.create(id);
208    
209                    Locale locale = LocaleUtil.getDefault();
210    
211                    String defaultLanguageId = ParamUtil.getString(
212                            serviceContext, "defaultLanguageId");
213    
214                    if (Validator.isNull(defaultLanguageId)) {
215                            defaultLanguageId = LocalizationUtil.getDefaultLocale(content);
216                    }
217    
218                    if (Validator.isNotNull(defaultLanguageId)) {
219                            locale = LocaleUtil.fromLanguageId(defaultLanguageId);
220                    }
221    
222                    String title = titleMap.get(locale);
223    
224                    content = format(
225                            user, groupId, articleId, version, false, content, structureId,
226                            images);
227    
228                    article.setResourcePrimKey(resourcePrimKey);
229                    article.setGroupId(groupId);
230                    article.setCompanyId(user.getCompanyId());
231                    article.setUserId(user.getUserId());
232                    article.setUserName(user.getFullName());
233                    article.setCreateDate(serviceContext.getCreateDate(now));
234                    article.setModifiedDate(serviceContext.getModifiedDate(now));
235                    article.setClassNameId(classNameId);
236                    article.setClassPK(classPK);
237                    article.setArticleId(articleId);
238                    article.setVersion(version);
239                    article.setTitleMap(titleMap, locale);
240                    article.setUrlTitle(
241                            getUniqueUrlTitle(id, articleId, title, null, serviceContext));
242                    article.setDescriptionMap(descriptionMap, locale);
243                    article.setContent(content);
244                    article.setType(type);
245                    article.setStructureId(structureId);
246                    article.setTemplateId(templateId);
247                    article.setLayoutUuid(layoutUuid);
248                    article.setDisplayDate(displayDate);
249                    article.setExpirationDate(expirationDate);
250                    article.setReviewDate(reviewDate);
251                    article.setIndexable(indexable);
252                    article.setSmallImage(smallImage);
253                    article.setSmallImageId(counterLocalService.increment());
254                    article.setSmallImageURL(smallImageURL);
255    
256                    if ((expirationDate == null) || expirationDate.after(now)) {
257                            article.setStatus(WorkflowConstants.STATUS_DRAFT);
258                    }
259                    else {
260                            article.setStatus(WorkflowConstants.STATUS_EXPIRED);
261                    }
262    
263                    journalArticlePersistence.update(article, false);
264    
265                    // Resources
266    
267                    if (serviceContext.isAddGroupPermissions() ||
268                            serviceContext.isAddGuestPermissions()) {
269    
270                            addArticleResources(
271                                    article, serviceContext.isAddGroupPermissions(),
272                                    serviceContext.isAddGuestPermissions());
273                    }
274                    else {
275                            addArticleResources(
276                                    article, serviceContext.getGroupPermissions(),
277                                    serviceContext.getGuestPermissions());
278                    }
279    
280                    // Expando
281    
282                    ExpandoBridge expandoBridge = article.getExpandoBridge();
283    
284                    expandoBridge.setAttributes(serviceContext);
285    
286                    // Small image
287    
288                    saveImages(
289                            smallImage, article.getSmallImageId(), smallImageFile,
290                            smallImageBytes);
291    
292                    // Asset
293    
294                    updateAsset(
295                            userId, article, serviceContext.getAssetCategoryIds(),
296                            serviceContext.getAssetTagNames(),
297                            serviceContext.getAssetLinkEntryIds());
298    
299                    // Message boards
300    
301                    if (PropsValues.JOURNAL_ARTICLE_COMMENTS_ENABLED) {
302                            mbMessageLocalService.addDiscussionMessage(
303                                    userId, article.getUserName(), groupId,
304                                    JournalArticle.class.getName(), resourcePrimKey,
305                                    WorkflowConstants.ACTION_PUBLISH);
306                    }
307    
308                    // Email
309    
310                    PortletPreferences preferences =
311                            ServiceContextUtil.getPortletPreferences(serviceContext);
312    
313                    sendEmail(
314                            article, articleURL, preferences, "requested", serviceContext);
315    
316                    // Workflow
317    
318                    if (classNameId == 0) {
319                            WorkflowHandlerRegistryUtil.startWorkflowInstance(
320                                    user.getCompanyId(), groupId, userId,
321                                    JournalArticle.class.getName(), article.getId(), article,
322                                    serviceContext);
323    
324                            if (serviceContext.getWorkflowAction() !=
325                                            WorkflowConstants.ACTION_PUBLISH) {
326    
327                                    // Indexer
328    
329                                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
330                                            JournalArticle.class);
331    
332                                    indexer.reindex(article);
333                            }
334                    }
335                    else {
336                            updateStatus(
337                                    userId, article, WorkflowConstants.STATUS_APPROVED, null,
338                                    serviceContext);
339                    }
340    
341                    return article;
342            }
343    
344            public void addArticleResources(
345                            JournalArticle article, boolean addGroupPermissions,
346                            boolean addGuestPermissions)
347                    throws PortalException, SystemException {
348    
349                    resourceLocalService.addResources(
350                            article.getCompanyId(), article.getGroupId(), article.getUserId(),
351                            JournalArticle.class.getName(), article.getResourcePrimKey(), false,
352                            addGroupPermissions, addGuestPermissions);
353            }
354    
355            public void addArticleResources(
356                            JournalArticle article, String[] groupPermissions,
357                            String[] guestPermissions)
358                    throws PortalException, SystemException {
359    
360                    resourceLocalService.addModelResources(
361                            article.getCompanyId(), article.getGroupId(), article.getUserId(),
362                            JournalArticle.class.getName(), article.getResourcePrimKey(),
363                            groupPermissions, guestPermissions);
364            }
365    
366            public void addArticleResources(
367                            long groupId, String articleId, boolean addGroupPermissions,
368                            boolean addGuestPermissions)
369                    throws PortalException, SystemException {
370    
371                    JournalArticle article = getLatestArticle(groupId, articleId);
372    
373                    addArticleResources(article, addGroupPermissions, addGuestPermissions);
374            }
375    
376            public void addArticleResources(
377                            long groupId, String articleId, String[] groupPermissions,
378                            String[] guestPermissions)
379                    throws PortalException, SystemException {
380    
381                    JournalArticle article = getLatestArticle(groupId, articleId);
382    
383                    addArticleResources(article, groupPermissions, guestPermissions);
384            }
385    
386            public JournalArticle checkArticleResourcePrimKey(
387                            long groupId, String articleId, double version)
388                    throws PortalException, SystemException {
389    
390                    JournalArticle article = journalArticlePersistence.findByG_A_V(
391                            groupId, articleId, version);
392    
393                    if (article.getResourcePrimKey() > 0) {
394                            return article;
395                    }
396    
397                    long resourcePrimKey =
398                            journalArticleResourceLocalService.getArticleResourcePrimKey(
399                                    groupId, articleId);
400    
401                    article.setResourcePrimKey(resourcePrimKey);
402    
403                    journalArticlePersistence.update(article, false);
404    
405                    return article;
406            }
407    
408            public void checkArticles() throws PortalException, SystemException {
409                    Date now = new Date();
410    
411                    List<JournalArticle> articles =
412                            journalArticleFinder.findByExpirationDate(
413                                    0, WorkflowConstants.STATUS_APPROVED,
414                                    new Date(now.getTime() + _JOURNAL_ARTICLE_CHECK_INTERVAL));
415    
416                    if (_log.isDebugEnabled()) {
417                            _log.debug("Expiring " + articles.size() + " articles");
418                    }
419    
420                    Set<Long> companyIds = new HashSet<Long>();
421    
422                    for (JournalArticle article : articles) {
423                            if (PropsValues.JOURNAL_ARTICLE_EXPIRE_ALL_VERSIONS) {
424                                    List<JournalArticle> currentArticles =
425                                            journalArticlePersistence.findByG_A(
426                                                    article.getGroupId(), article.getArticleId(),
427                                                    QueryUtil.ALL_POS, QueryUtil.ALL_POS,
428                                                    new ArticleVersionComparator(true));
429    
430                                    for (JournalArticle currentArticle : currentArticles) {
431                                            currentArticle.setExpirationDate(
432                                                    article.getExpirationDate());
433                                            currentArticle.setStatus(WorkflowConstants.STATUS_EXPIRED);
434    
435                                            journalArticlePersistence.update(currentArticle, false);
436                                    }
437                            }
438                            else {
439                                    article.setStatus(WorkflowConstants.STATUS_EXPIRED);
440    
441                                    journalArticlePersistence.update(article, false);
442                            }
443    
444                            updatePreviousApprovedArticle(article);
445    
446                            JournalContentUtil.clearCache(
447                                    article.getGroupId(), article.getArticleId(),
448                                    article.getTemplateId());
449    
450                            companyIds.add(article.getCompanyId());
451                    }
452    
453                    for (long companyId : companyIds) {
454                            CacheUtil.clearCache(companyId);
455                    }
456    
457                    articles = journalArticleFinder.findByReviewDate(
458                            0, now, new Date(now.getTime() - _JOURNAL_ARTICLE_CHECK_INTERVAL));
459    
460                    if (_log.isDebugEnabled()) {
461                            _log.debug(
462                                    "Sending review notifications for " + articles.size() +
463                                            " articles");
464                    }
465    
466                    for (JournalArticle article : articles) {
467                            String articleURL = StringPool.BLANK;
468    
469                            long ownerId = article.getGroupId();
470                            int ownerType = PortletKeys.PREFS_OWNER_TYPE_GROUP;
471                            long plid = PortletKeys.PREFS_PLID_SHARED;
472                            String portletId = PortletKeys.JOURNAL;
473    
474                            PortletPreferences preferences =
475                                    portletPreferencesLocalService.getPreferences(
476                                            article.getCompanyId(), ownerId, ownerType, plid,
477                                            portletId);
478    
479                            sendEmail(
480                                    article, articleURL, preferences, "review",
481                                    new ServiceContext());
482                    }
483            }
484    
485            public void checkNewLine(long groupId, String articleId, double version)
486                    throws PortalException, SystemException {
487    
488                    JournalArticle article = journalArticlePersistence.findByG_A_V(
489                            groupId, articleId, version);
490    
491                    String content = GetterUtil.getString(article.getContent());
492    
493                    if (content.indexOf("\\n") != -1) {
494                            content = StringUtil.replace(
495                                    content, new String[] {"\\n", "\\r"},
496                                    new String[] {"\n", "\r"});
497    
498                            article.setContent(content);
499    
500                            journalArticlePersistence.update(article, false);
501                    }
502            }
503    
504            public void checkStructure(long groupId, String articleId, double version)
505                    throws PortalException, SystemException {
506    
507                    JournalArticle article = journalArticlePersistence.findByG_A_V(
508                            groupId, articleId, version);
509    
510                    if (Validator.isNull(article.getStructureId())) {
511                            return;
512                    }
513    
514                    try {
515                            checkStructure(article);
516                    }
517                    catch (DocumentException de) {
518                            _log.error(de, de);
519                    }
520            }
521    
522            public JournalArticle copyArticle(
523                            long userId, long groupId, String oldArticleId, String newArticleId,
524                            boolean autoArticleId, double version)
525                    throws PortalException, SystemException {
526    
527                    // Article
528    
529                    User user = userPersistence.findByPrimaryKey(userId);
530                    oldArticleId = oldArticleId.trim().toUpperCase();
531                    newArticleId = newArticleId.trim().toUpperCase();
532                    Date now = new Date();
533    
534                    JournalArticle oldArticle = journalArticlePersistence.findByG_A_V(
535                            groupId, oldArticleId, version);
536    
537                    if (autoArticleId) {
538                            newArticleId = String.valueOf(counterLocalService.increment());
539                    }
540                    else {
541                            validate(groupId, newArticleId);
542                    }
543    
544                    long id = counterLocalService.increment();
545    
546                    long resourcePrimKey =
547                            journalArticleResourceLocalService.getArticleResourcePrimKey(
548                                    groupId, newArticleId);
549    
550                    JournalArticle newArticle = journalArticlePersistence.create(id);
551    
552                    newArticle.setResourcePrimKey(resourcePrimKey);
553                    newArticle.setGroupId(groupId);
554                    newArticle.setCompanyId(user.getCompanyId());
555                    newArticle.setUserId(user.getUserId());
556                    newArticle.setUserName(user.getFullName());
557                    newArticle.setCreateDate(now);
558                    newArticle.setModifiedDate(now);
559                    newArticle.setArticleId(newArticleId);
560                    newArticle.setVersion(JournalArticleConstants.VERSION_DEFAULT);
561                    newArticle.setTitle(oldArticle.getTitle());
562                    newArticle.setDescription(oldArticle.getDescription());
563    
564                    try {
565                            copyArticleImages(oldArticle, newArticle);
566                    }
567                    catch (Exception e) {
568                            newArticle.setContent(oldArticle.getContent());
569                    }
570    
571                    newArticle.setType(oldArticle.getType());
572                    newArticle.setStructureId(oldArticle.getStructureId());
573                    newArticle.setTemplateId(oldArticle.getTemplateId());
574                    newArticle.setLayoutUuid(oldArticle.getLayoutUuid());
575                    newArticle.setDisplayDate(oldArticle.getDisplayDate());
576                    newArticle.setExpirationDate(oldArticle.getExpirationDate());
577                    newArticle.setReviewDate(oldArticle.getReviewDate());
578                    newArticle.setIndexable(oldArticle.isIndexable());
579                    newArticle.setSmallImage(oldArticle.isSmallImage());
580                    newArticle.setSmallImageId(counterLocalService.increment());
581                    newArticle.setSmallImageURL(oldArticle.getSmallImageURL());
582                    newArticle.setStatus(oldArticle.getStatus());
583    
584                    journalArticlePersistence.update(newArticle, false);
585    
586                    // Resources
587    
588                    addArticleResources(newArticle, true, true);
589    
590                    // Small image
591    
592                    if (oldArticle.getSmallImage()) {
593                            Image image = imageLocalService.getImage(
594                                    oldArticle.getSmallImageId());
595    
596                            byte[] smallImageBytes = image.getTextObj();
597    
598                            imageLocalService.updateImage(
599                                    newArticle.getSmallImageId(), smallImageBytes);
600                    }
601    
602                    // Asset
603    
604                    long[] assetCategoryIds = assetCategoryLocalService.getCategoryIds(
605                            JournalArticle.class.getName(), oldArticle.getResourcePrimKey());
606                    String[] assetTagNames = assetTagLocalService.getTagNames(
607                            JournalArticle.class.getName(), oldArticle.getResourcePrimKey());
608    
609                    updateAsset(userId, newArticle, assetCategoryIds, assetTagNames, null);
610    
611                    return newArticle;
612            }
613    
614            public void deleteArticle(
615                            JournalArticle article, String articleURL,
616                            ServiceContext serviceContext)
617                    throws PortalException, SystemException {
618    
619                    if (article.isApproved() &&
620                            isLatestVersion(
621                                    article.getGroupId(), article.getArticleId(),
622                                    article.getVersion(), WorkflowConstants.STATUS_APPROVED)) {
623    
624                            updatePreviousApprovedArticle(article);
625                    }
626    
627                    // Email
628    
629                    PortletPreferences preferences =
630                            ServiceContextUtil.getPortletPreferences(serviceContext);
631    
632                    if ((preferences != null) && !article.isApproved() &&
633                            isLatestVersion(
634                                    article.getGroupId(), article.getArticleId(),
635                                    article.getVersion())) {
636    
637                            sendEmail(
638                                    article, articleURL, preferences, "denied", serviceContext);
639                    }
640    
641                    // Images
642    
643                    journalArticleImageLocalService.deleteImages(
644                            article.getGroupId(), article.getArticleId(), article.getVersion());
645    
646                    // Workflow
647    
648                    if (!article.isDraft()) {
649                            workflowInstanceLinkLocalService.deleteWorkflowInstanceLink(
650                                    article.getCompanyId(), article.getGroupId(),
651                                    JournalArticle.class.getName(), article.getId());
652                    }
653    
654                    int articlesCount = journalArticlePersistence.countByG_A(
655                            article.getGroupId(), article.getArticleId());
656    
657                    if (articlesCount == 1) {
658    
659                            // Subscriptions
660    
661                            subscriptionLocalService.deleteSubscriptions(
662                                    article.getCompanyId(), JournalArticle.class.getName(),
663                                    article.getResourcePrimKey());
664    
665                            // Ratings
666    
667                            ratingsStatsLocalService.deleteStats(
668                                    JournalArticle.class.getName(), article.getResourcePrimKey());
669    
670                            // Message boards
671    
672                            mbMessageLocalService.deleteDiscussionMessages(
673                                    JournalArticle.class.getName(), article.getResourcePrimKey());
674    
675                            // Asset
676    
677                            assetEntryLocalService.deleteEntry(
678                                    JournalArticle.class.getName(), article.getResourcePrimKey());
679    
680                            // Content searches
681    
682                            journalContentSearchLocalService.deleteArticleContentSearches(
683                                    article.getGroupId(), article.getArticleId());
684    
685                            // Small image
686    
687                            imageLocalService.deleteImage(article.getSmallImageId());
688    
689                            // Expando
690    
691                            expandoValueLocalService.deleteValues(
692                                    JournalArticle.class.getName(), article.getId());
693    
694                            // Resources
695    
696                            resourceLocalService.deleteResource(
697                                    article.getCompanyId(), JournalArticle.class.getName(),
698                                    ResourceConstants.SCOPE_INDIVIDUAL,
699                                    article.getResourcePrimKey());
700    
701                            // Resource
702    
703                            try {
704                                    journalArticleResourceLocalService.deleteArticleResource(
705                                            article.getGroupId(), article.getArticleId());
706                            }
707                            catch (NoSuchArticleResourceException nsare) {
708                            }
709                    }
710    
711                    // Article
712    
713                    journalArticlePersistence.remove(article);
714            }
715    
716            public void deleteArticle(
717                            long groupId, String articleId, double version, String articleURL,
718                            ServiceContext serviceContext)
719                    throws PortalException, SystemException {
720    
721                    JournalArticle article = journalArticlePersistence.findByG_A_V(
722                            groupId, articleId, version);
723    
724                    deleteArticle(article, articleURL, serviceContext);
725            }
726    
727            public void deleteArticle(
728                            long groupId, String articleId, ServiceContext serviceContext)
729                    throws PortalException, SystemException {
730    
731                    List<JournalArticle> articles = journalArticlePersistence.findByG_A(
732                            groupId, articleId, QueryUtil.ALL_POS, QueryUtil.ALL_POS,
733                            new ArticleVersionComparator(true));
734    
735                    for (JournalArticle article : articles) {
736                            deleteArticle(article, null, serviceContext);
737                    }
738            }
739    
740            public void deleteArticles(long groupId)
741                    throws PortalException, SystemException {
742    
743                    for (JournalArticle article :
744                                    journalArticlePersistence.findByGroupId(groupId)) {
745    
746                            deleteArticle(article, null, null);
747                    }
748            }
749    
750            public void deleteLayoutArticleReferences(long groupId, String layoutUuid)
751                    throws SystemException {
752    
753                    List<JournalArticle> articles = journalArticlePersistence.findByG_L(
754                            groupId, layoutUuid);
755    
756                    for (JournalArticle article : articles) {
757                            article.setLayoutUuid(StringPool.BLANK);
758    
759                            journalArticlePersistence.update(article, false);
760                    }
761            }
762    
763            public JournalArticle expireArticle(
764                            long userId, long groupId, String articleId, double version,
765                            String articleURL, ServiceContext serviceContext)
766                    throws PortalException, SystemException {
767    
768                    return updateStatus(
769                            userId, groupId, articleId, version,
770                            WorkflowConstants.STATUS_EXPIRED, articleURL, serviceContext);
771            }
772    
773            public void expireArticle(
774                            long userId, long groupId, String articleId, String articleURL,
775                            ServiceContext serviceContext)
776                    throws PortalException, SystemException {
777    
778                    if (PropsValues.JOURNAL_ARTICLE_EXPIRE_ALL_VERSIONS) {
779                            List<JournalArticle> articles = journalArticlePersistence.findByG_A(
780                                    groupId, articleId, QueryUtil.ALL_POS, QueryUtil.ALL_POS,
781                                    new ArticleVersionComparator(true));
782    
783                            for (JournalArticle article : articles) {
784                                    expireArticle(
785                                            userId, groupId, article.getArticleId(),
786                                            article.getVersion(), articleURL, serviceContext);
787                            }
788                    }
789                    else {
790                            JournalArticle article = getLatestArticle(
791                                    groupId, articleId, WorkflowConstants.STATUS_APPROVED);
792    
793                            expireArticle(
794                                    userId, groupId, article.getArticleId(), article.getVersion(),
795                                    articleURL, serviceContext);
796                    }
797            }
798    
799            public JournalArticle getArticle(long id)
800                    throws PortalException, SystemException {
801    
802                    return journalArticlePersistence.findByPrimaryKey(id);
803            }
804    
805            public JournalArticle getArticle(long groupId, String articleId)
806                    throws PortalException, SystemException {
807    
808                    // Get the latest article that is approved, if none are approved, get
809                    // the latest unapproved article
810    
811                    try {
812                            return getLatestArticle(
813                                    groupId, articleId, WorkflowConstants.STATUS_APPROVED);
814                    }
815                    catch (NoSuchArticleException nsae) {
816                            return getLatestArticle(
817                                    groupId, articleId, WorkflowConstants.STATUS_ANY);
818                    }
819            }
820    
821            public JournalArticle getArticle(
822                            long groupId, String articleId, double version)
823                    throws PortalException, SystemException {
824    
825                    return journalArticlePersistence.findByG_A_V(
826                            groupId, articleId, version);
827            }
828    
829            public JournalArticle getArticle(
830                            long groupId, String className, long classPK)
831                    throws PortalException, SystemException {
832    
833                    long classNameId = PortalUtil.getClassNameId(className);
834    
835                    List<JournalArticle> articles = journalArticlePersistence.findByG_C_C(
836                            groupId, classNameId, classPK);
837    
838                    if (articles.isEmpty()) {
839                            throw new NoSuchArticleException(
840                                    "No approved JournalArticle exists with the key {groupId="
841                                            + groupId + ", className=" + className + ", classPK=" +
842                                                    classPK + "}");
843                    }
844    
845                    return articles.get(0);
846            }
847    
848            public JournalArticle getArticleByUrlTitle(long groupId, String urlTitle)
849                    throws PortalException, SystemException {
850    
851                    // Get the latest article that is approved, if none are approved, get
852                    // the latest unapproved article
853    
854                    try {
855                            return getLatestArticleByUrlTitle(
856                                    groupId, urlTitle, WorkflowConstants.STATUS_APPROVED);
857                    }
858                    catch (NoSuchArticleException nsae) {
859                            return getLatestArticleByUrlTitle(
860                                    groupId, urlTitle, WorkflowConstants.STATUS_PENDING);
861                    }
862            }
863    
864            public String getArticleContent(
865                            JournalArticle article, String templateId, String viewMode,
866                            String languageId, ThemeDisplay themeDisplay)
867                    throws PortalException, SystemException {
868    
869                    JournalArticleDisplay articleDisplay = getArticleDisplay(
870                            article, templateId, viewMode, languageId, 1, null, themeDisplay);
871    
872                    if (articleDisplay == null) {
873                            return StringPool.BLANK;
874                    }
875                    else {
876                            return articleDisplay.getContent();
877                    }
878            }
879    
880            public String getArticleContent(
881                            long groupId, String articleId, double version, String viewMode,
882                            String templateId, String languageId, ThemeDisplay themeDisplay)
883                    throws PortalException, SystemException {
884    
885                    JournalArticleDisplay articleDisplay = getArticleDisplay(
886                            groupId, articleId, version, templateId, viewMode, languageId,
887                            themeDisplay);
888    
889                    if (articleDisplay == null) {
890                            return StringPool.BLANK;
891                    }
892                    else {
893                            return articleDisplay.getContent();
894                    }
895            }
896    
897            public String getArticleContent(
898                            long groupId, String articleId, double version, String viewMode,
899                            String languageId, ThemeDisplay themeDisplay)
900                    throws PortalException, SystemException {
901    
902                    return getArticleContent(
903                            groupId, articleId, version, viewMode, null, languageId,
904                            themeDisplay);
905            }
906    
907            public String getArticleContent(
908                            long groupId, String articleId, String viewMode, String templateId,
909                            String languageId, ThemeDisplay themeDisplay)
910                    throws PortalException, SystemException {
911    
912                    JournalArticleDisplay articleDisplay = getArticleDisplay(
913                            groupId, articleId, templateId, viewMode, languageId, themeDisplay);
914    
915                    return articleDisplay.getContent();
916            }
917    
918            public String getArticleContent(
919                            long groupId, String articleId, String viewMode, String languageId,
920                            ThemeDisplay themeDisplay)
921                    throws PortalException, SystemException {
922    
923                    return getArticleContent(
924                            groupId, articleId, viewMode, null, languageId, themeDisplay);
925            }
926    
927            public JournalArticleDisplay getArticleDisplay(
928                            JournalArticle article, String templateId, String viewMode,
929                            String languageId, int page, String xmlRequest,
930                            ThemeDisplay themeDisplay)
931                    throws PortalException, SystemException {
932    
933                    String content = null;
934    
935                    if (page < 1) {
936                            page = 1;
937                    }
938    
939                    int numberOfPages = 1;
940                    boolean paginate = false;
941                    boolean pageFlow = false;
942    
943                    boolean cacheable = true;
944    
945                    if (Validator.isNull(xmlRequest)) {
946                            xmlRequest = "<request />";
947                    }
948    
949                    Map<String, String> tokens = JournalUtil.getTokens(
950                            article.getGroupId(), themeDisplay, xmlRequest);
951    
952                    tokens.put(
953                            "article_resource_pk",
954                            String.valueOf(article.getResourcePrimKey()));
955    
956                    String defaultTemplateId = article.getTemplateId();
957    
958                    if (article.isTemplateDriven()) {
959                            if (Validator.isNull(templateId)) {
960                                    templateId = defaultTemplateId;
961                            }
962    
963                            tokens.put("structure_id", article.getStructureId());
964                            tokens.put("template_id", templateId);
965                    }
966    
967                    String xml = article.getContent();
968    
969                    try {
970                            Document document = null;
971    
972                            Element rootElement = null;
973    
974                            if (article.isTemplateDriven()) {
975                                    document = SAXReaderUtil.read(xml);
976    
977                                    rootElement = document.getRootElement();
978    
979                                    Document requestDocument = SAXReaderUtil.read(xmlRequest);
980    
981                                    List<Element> pages = rootElement.elements("page");
982    
983                                    if (!pages.isEmpty()) {
984                                            pageFlow = true;
985    
986                                            String targetPage = requestDocument.valueOf(
987                                                    "/request/parameters/parameter[name='targetPage']/" +
988                                                            "value");
989    
990                                            Element pageElement = null;
991    
992                                            if (Validator.isNotNull(targetPage)) {
993                                                    XPath xPathSelector = SAXReaderUtil.createXPath(
994                                                            "/root/page[@id = '" + targetPage + "']");
995    
996                                                    pageElement = (Element)xPathSelector.selectSingleNode(
997                                                            document);
998                                            }
999    
1000                                            if (pageElement != null) {
1001                                                    document = SAXReaderUtil.createDocument(pageElement);
1002    
1003                                                    rootElement = document.getRootElement();
1004    
1005                                                    numberOfPages = pages.size();
1006                                            }
1007                                            else {
1008                                                    if (page > pages.size()) {
1009                                                            page = 1;
1010                                                    }
1011    
1012                                                    pageElement = pages.get(page - 1);
1013    
1014                                                    document = SAXReaderUtil.createDocument(pageElement);
1015    
1016                                                    rootElement = document.getRootElement();
1017    
1018                                                    numberOfPages = pages.size();
1019                                                    paginate = true;
1020                                            }
1021                                    }
1022    
1023                                    rootElement.add(requestDocument.getRootElement().createCopy());
1024    
1025                                    JournalUtil.addAllReservedEls(
1026                                            rootElement, tokens, article, languageId);
1027    
1028                                    xml = DDMXMLUtil.formatXML(document);
1029                            }
1030                    }
1031                    catch (DocumentException de) {
1032                            throw new SystemException(de);
1033                    }
1034                    catch (IOException ioe) {
1035                            throw new SystemException(ioe);
1036                    }
1037    
1038                    try {
1039                            if (_log.isDebugEnabled()) {
1040                                    _log.debug(
1041                                            "Transforming " + article.getArticleId() + " " +
1042                                                    article.getVersion() + " " + languageId);
1043                            }
1044    
1045                            String script = null;
1046                            String langType = null;
1047    
1048                            if (article.isTemplateDriven()) {
1049    
1050                                    // Try with specified template first (in the current group and
1051                                    // the global group). If a template is not specified, use the
1052                                    // default one. If the specified template does not exit, use the
1053                                    // default one. If the default one does not exist, throw an
1054                                    // exception.
1055    
1056                                    JournalTemplate template = null;
1057    
1058                                    try {
1059                                            template = journalTemplatePersistence.findByG_T(
1060                                                    article.getGroupId(), templateId);
1061                                    }
1062                                    catch (NoSuchTemplateException nste1) {
1063                                            try {
1064                                                    Group companyGroup = groupLocalService.getCompanyGroup(
1065                                                            article.getCompanyId());
1066    
1067                                                    template = journalTemplatePersistence.findByG_T(
1068                                                            companyGroup.getGroupId(), templateId);
1069    
1070                                                    tokens.put(
1071                                                            "company_group_id",
1072                                                            String.valueOf(companyGroup.getGroupId()));
1073                                            }
1074                                            catch (NoSuchTemplateException nste2) {
1075                                                    if (!defaultTemplateId.equals(templateId)) {
1076                                                            template = journalTemplatePersistence.findByG_T(
1077                                                                    article.getGroupId(), defaultTemplateId);
1078                                                    }
1079                                                    else {
1080                                                            throw nste1;
1081                                                    }
1082                                            }
1083                                    }
1084    
1085                                    script = template.getXsl();
1086                                    langType = template.getLangType();
1087                                    cacheable = template.isCacheable();
1088                            }
1089    
1090                            content = JournalUtil.transform(
1091                                    themeDisplay, tokens, viewMode, languageId, xml, script,
1092                                    langType);
1093    
1094                            if (!pageFlow) {
1095                                    String[] pieces = StringUtil.split(
1096                                            content, PropsValues.JOURNAL_ARTICLE_TOKEN_PAGE_BREAK);
1097    
1098                                    if (pieces.length > 1) {
1099                                            if (page > pieces.length) {
1100                                                    page = 1;
1101                                            }
1102    
1103                                            content = pieces[page - 1];
1104                                            numberOfPages = pieces.length;
1105                                            paginate = true;
1106                                    }
1107                            }
1108                    }
1109                    catch (Exception e) {
1110                            throw new SystemException(e);
1111                    }
1112    
1113                    return new JournalArticleDisplayImpl(
1114                            article.getCompanyId(), article.getId(),
1115                            article.getResourcePrimKey(), article.getGroupId(),
1116                            article.getUserId(), article.getArticleId(), article.getVersion(),
1117                            article.getTitle(languageId), article.getUrlTitle(),
1118                            article.getDescription(languageId), article.getAvailableLocales(),
1119                            content, article.getType(), article.getStructureId(), templateId,
1120                            article.isSmallImage(), article.getSmallImageId(),
1121                            article.getSmallImageURL(), numberOfPages, page, paginate,
1122                            cacheable);
1123            }
1124    
1125            public JournalArticleDisplay getArticleDisplay(
1126                            long groupId, String articleId, double version, String templateId,
1127                            String viewMode, String languageId, int page, String xmlRequest,
1128                            ThemeDisplay themeDisplay)
1129                    throws PortalException, SystemException {
1130    
1131                    Date now = new Date();
1132    
1133                    JournalArticle article = journalArticlePersistence.findByG_A_V(
1134                            groupId, articleId, version);
1135    
1136                    if (article.isExpired()) {
1137                            Date expirationDate = article.getExpirationDate();
1138    
1139                            if ((expirationDate != null) && expirationDate.before(now)) {
1140                                    return null;
1141                            }
1142                    }
1143    
1144                    if (article.getDisplayDate().after(now)) {
1145                            return null;
1146                    }
1147    
1148                    return getArticleDisplay(
1149                            article, templateId, viewMode, languageId, page, xmlRequest,
1150                            themeDisplay);
1151            }
1152    
1153            public JournalArticleDisplay getArticleDisplay(
1154                            long groupId, String articleId, double version, String templateId,
1155                            String viewMode, String languageId, ThemeDisplay themeDisplay)
1156                    throws PortalException, SystemException {
1157    
1158                    return getArticleDisplay(
1159                            groupId, articleId, version, templateId, viewMode, languageId, 1,
1160                            null, themeDisplay);
1161            }
1162    
1163            public JournalArticleDisplay getArticleDisplay(
1164                            long groupId, String articleId, String viewMode, String languageId,
1165                            int page, String xmlRequest, ThemeDisplay themeDisplay)
1166                    throws PortalException, SystemException {
1167    
1168                    return getArticleDisplay(
1169                            groupId, articleId, null, viewMode, languageId, page, xmlRequest,
1170                            themeDisplay);
1171            }
1172    
1173            public JournalArticleDisplay getArticleDisplay(
1174                            long groupId, String articleId, String templateId, String viewMode,
1175                            String languageId, int page, String xmlRequest,
1176                            ThemeDisplay themeDisplay)
1177                    throws PortalException, SystemException {
1178    
1179                    JournalArticle article = getDisplayArticle(groupId, articleId);
1180    
1181                    return getArticleDisplay(
1182                            groupId, articleId, article.getVersion(), templateId, viewMode,
1183                            languageId, page, xmlRequest, themeDisplay);
1184            }
1185    
1186            public JournalArticleDisplay getArticleDisplay(
1187                            long groupId, String articleId, String templateId, String viewMode,
1188                            String languageId, ThemeDisplay themeDisplay)
1189                    throws PortalException, SystemException {
1190    
1191                    JournalArticle article = getDisplayArticle(groupId, articleId);
1192    
1193                    return getArticleDisplay(
1194                            groupId, articleId, article.getVersion(), templateId, viewMode,
1195                            languageId, themeDisplay);
1196            }
1197    
1198            public JournalArticleDisplay getArticleDisplay(
1199                            long groupId, String articleId, String viewMode, String languageId,
1200                            ThemeDisplay themeDisplay)
1201                    throws PortalException, SystemException {
1202    
1203                    return getArticleDisplay(
1204                            groupId, articleId, null, viewMode, languageId, themeDisplay);
1205            }
1206    
1207            public List<JournalArticle> getArticles() throws SystemException {
1208                    return journalArticlePersistence.findAll();
1209            }
1210    
1211            public List<JournalArticle> getArticles(long groupId)
1212                    throws SystemException {
1213    
1214                    return journalArticlePersistence.findByGroupId(groupId);
1215            }
1216    
1217            public List<JournalArticle> getArticles(long groupId, int start, int end)
1218                    throws SystemException {
1219    
1220                    return journalArticlePersistence.findByGroupId(groupId, start, end);
1221            }
1222    
1223            public List<JournalArticle> getArticles(
1224                            long groupId, int start, int end, OrderByComparator obc)
1225                    throws SystemException {
1226    
1227                    return journalArticlePersistence.findByGroupId(
1228                            groupId, start, end, obc);
1229            }
1230    
1231            public List<JournalArticle> getArticles(long groupId, String articleId)
1232                    throws SystemException {
1233    
1234                    return journalArticlePersistence.findByG_A(groupId, articleId);
1235            }
1236    
1237            public List<JournalArticle> getArticlesBySmallImageId(long smallImageId)
1238                    throws SystemException {
1239    
1240                    return journalArticlePersistence.findBySmallImageId(smallImageId);
1241            }
1242    
1243            public int getArticlesCount(long groupId) throws SystemException {
1244                    return journalArticlePersistence.countByGroupId(groupId);
1245            }
1246    
1247            public List<JournalArticle> getCompanyArticles(
1248                            long companyId, double version, int status, int start, int end)
1249                    throws SystemException {
1250    
1251                    if (status == WorkflowConstants.STATUS_ANY) {
1252                            return journalArticlePersistence.findByC_V(
1253                                    companyId, version, start, end, new ArticleIDComparator(true));
1254                    }
1255                    else {
1256                            return journalArticlePersistence.findByC_V_ST(
1257                                    companyId, version, status, start, end,
1258                                    new ArticleIDComparator(true));
1259                    }
1260            }
1261    
1262            public List<JournalArticle> getCompanyArticles(
1263                            long companyId, int status, int start, int end)
1264                    throws SystemException {
1265    
1266                    if (status == WorkflowConstants.STATUS_ANY) {
1267                            return journalArticlePersistence.findByCompanyId(
1268                                    companyId, start, end, new ArticleIDComparator(true));
1269                    }
1270                    else {
1271                            return journalArticlePersistence.findByC_ST(
1272                                    companyId, status, start, end, new ArticleIDComparator(true));
1273                    }
1274            }
1275    
1276            public int getCompanyArticlesCount(
1277                            long companyId, double version, int status, int start, int end)
1278                    throws SystemException {
1279    
1280                    if (status == WorkflowConstants.STATUS_ANY) {
1281                            return journalArticlePersistence.countByC_V(companyId, version);
1282                    }
1283                    else {
1284                            return journalArticlePersistence.countByC_V_ST(
1285                                    companyId, version, status);
1286                    }
1287            }
1288    
1289            public int getCompanyArticlesCount(long companyId, int status)
1290                    throws SystemException {
1291    
1292                    if (status == WorkflowConstants.STATUS_ANY) {
1293                            return journalArticlePersistence.countByCompanyId(companyId);
1294                    }
1295                    else {
1296                            return journalArticlePersistence.countByC_ST(companyId, status);
1297                    }
1298            }
1299    
1300            public JournalArticle getDisplayArticle(long groupId, String articleId)
1301                    throws PortalException, SystemException {
1302    
1303                    List<JournalArticle> articles = journalArticlePersistence.findByG_A_ST(
1304                            groupId, articleId, WorkflowConstants.STATUS_APPROVED);
1305    
1306                    if (articles.isEmpty()) {
1307                            throw new NoSuchArticleException(
1308                                    "No approved JournalArticle exists with the key {groupId=" +
1309                                            groupId + ", " + "articleId=" + articleId + "}");
1310    
1311                    }
1312    
1313                    Date now = new Date();
1314    
1315                    for (int i = 0; i < articles.size(); i++) {
1316                            JournalArticle article = articles.get(i);
1317    
1318                            Date expirationDate = article.getExpirationDate();
1319    
1320                            if (article.getDisplayDate().before(now) &&
1321                                    ((expirationDate == null) || expirationDate.after(now))) {
1322    
1323                                    return article;
1324                            }
1325                    }
1326    
1327                    return articles.get(0);
1328            }
1329    
1330            public JournalArticle getDisplayArticleByUrlTitle(
1331                            long groupId, String urlTitle)
1332                    throws PortalException, SystemException {
1333    
1334                    List<JournalArticle> articles = null;
1335    
1336                    OrderByComparator orderByComparator = new ArticleVersionComparator();
1337    
1338                    articles = journalArticlePersistence.findByG_UT_ST(
1339                            groupId, urlTitle, WorkflowConstants.STATUS_APPROVED,
1340                            QueryUtil.ALL_POS, QueryUtil.ALL_POS, orderByComparator);
1341    
1342                    if (articles.isEmpty()) {
1343                            throw new NoSuchArticleException(
1344                                    "No JournalArticle exists with the key {groupId=" + groupId +
1345                                            ", urlTitle=" + urlTitle + "}");
1346                    }
1347    
1348                    Date now = new Date();
1349    
1350                    for (JournalArticle article : articles) {
1351                            Date expirationDate = article.getExpirationDate();
1352    
1353                            if (article.getDisplayDate().before(now) &&
1354                                    ((expirationDate == null) || expirationDate.after(now))) {
1355    
1356                                    return article;
1357                            }
1358                    }
1359    
1360                    return articles.get(0);
1361            }
1362    
1363            public JournalArticle getLatestArticle(long resourcePrimKey)
1364                    throws PortalException, SystemException {
1365    
1366                    return getLatestArticle(resourcePrimKey, WorkflowConstants.STATUS_ANY);
1367            }
1368    
1369            public JournalArticle getLatestArticle(long resourcePrimKey, int status)
1370                    throws PortalException, SystemException {
1371    
1372                    return getLatestArticle(resourcePrimKey, status, true);
1373            }
1374    
1375            public JournalArticle getLatestArticle(
1376                            long resourcePrimKey, int status, boolean preferApproved)
1377                    throws PortalException, SystemException {
1378    
1379                    List<JournalArticle> articles = null;
1380    
1381                    OrderByComparator orderByComparator = new ArticleVersionComparator();
1382    
1383                    if (status == WorkflowConstants.STATUS_ANY) {
1384                            if (preferApproved) {
1385                                    articles = journalArticlePersistence.findByR_ST(
1386                                            resourcePrimKey, WorkflowConstants.STATUS_APPROVED, 0, 1,
1387                                            orderByComparator);
1388                            }
1389    
1390                            if ((articles == null) || (articles.size() == 0)) {
1391                                    articles = journalArticlePersistence.findByResourcePrimKey(
1392                                            resourcePrimKey, 0, 1, orderByComparator);
1393                            }
1394                    }
1395                    else {
1396                            articles = journalArticlePersistence.findByR_ST(
1397                                    resourcePrimKey, status, 0, 1, orderByComparator);
1398                    }
1399    
1400                    if (articles.isEmpty()) {
1401                            throw new NoSuchArticleException(
1402                                    "No JournalArticle exists with the key {resourcePrimKey=" +
1403                                            resourcePrimKey + "}");
1404                    }
1405    
1406                    return articles.get(0);
1407            }
1408    
1409            public JournalArticle getLatestArticle(long groupId, String articleId)
1410                    throws PortalException, SystemException {
1411    
1412                    return getLatestArticle(
1413                            groupId, articleId, WorkflowConstants.STATUS_ANY);
1414            }
1415    
1416            public JournalArticle getLatestArticle(
1417                            long groupId, String articleId, int status)
1418                    throws PortalException, SystemException {
1419    
1420                    List<JournalArticle> articles = null;
1421    
1422                    OrderByComparator orderByComparator = new ArticleVersionComparator();
1423    
1424                    if (status == WorkflowConstants.STATUS_ANY) {
1425                            articles = journalArticlePersistence.findByG_A(
1426                                    groupId, articleId, 0, 1, orderByComparator);
1427                    }
1428                    else {
1429                            articles = journalArticlePersistence.findByG_A_ST(
1430                                    groupId, articleId, status, 0, 1, orderByComparator);
1431                    }
1432    
1433                    if (articles.isEmpty()) {
1434                            throw new NoSuchArticleException(
1435                                    "No JournalArticle exists with the key {groupId=" + groupId +
1436                                            ", articleId=" + articleId + ", status=" + status + "}");
1437                    }
1438    
1439                    return articles.get(0);
1440            }
1441    
1442            public JournalArticle getLatestArticle(
1443                            long groupId, String className, long classPK)
1444                    throws PortalException, SystemException {
1445    
1446                    long classNameId = PortalUtil.getClassNameId(className);
1447    
1448                    List<JournalArticle> articles = journalArticlePersistence.findByG_C_C(
1449                            groupId, classNameId, classPK, 0, 1,
1450                            new ArticleVersionComparator());
1451    
1452                    if (articles.isEmpty()) {
1453                            throw new NoSuchArticleException(
1454                                    "No JournalArticle exists with the key {groupId=" + groupId +
1455                                            ", className=" + className + ", classPK =" + classPK + "}");
1456                    }
1457    
1458                    return articles.get(0);
1459            }
1460    
1461            public JournalArticle getLatestArticleByUrlTitle(
1462                            long groupId, String urlTitle, int status)
1463                    throws PortalException, SystemException {
1464    
1465                    List<JournalArticle> articles = null;
1466    
1467                    OrderByComparator orderByComparator = new ArticleVersionComparator();
1468    
1469                    if (status == WorkflowConstants.STATUS_ANY) {
1470                            articles = journalArticlePersistence.findByG_UT(
1471                                    groupId, urlTitle, 0, 1, orderByComparator);
1472                    }
1473                    else {
1474                            articles = journalArticlePersistence.findByG_UT_ST(
1475                                    groupId, urlTitle, status, 0, 1, orderByComparator);
1476                    }
1477    
1478                    if (articles.isEmpty()) {
1479                            throw new NoSuchArticleException(
1480                                    "No JournalArticle exists with the key {groupId=" + groupId +
1481                                            ", urlTitle=" + urlTitle + ", status=" + status + "}");
1482                    }
1483    
1484                    return articles.get(0);
1485            }
1486    
1487            public double getLatestVersion(long groupId, String articleId)
1488                    throws PortalException, SystemException {
1489    
1490                    JournalArticle article = getLatestArticle(groupId, articleId);
1491    
1492                    return article.getVersion();
1493            }
1494    
1495            public double getLatestVersion(long groupId, String articleId, int status)
1496                    throws PortalException, SystemException {
1497    
1498                    JournalArticle article = getLatestArticle(groupId, articleId, status);
1499    
1500                    return article.getVersion();
1501            }
1502    
1503            public List<JournalArticle> getStructureArticles(
1504                            long groupId, String structureId)
1505                    throws SystemException {
1506    
1507                    return journalArticlePersistence.findByG_S(groupId, structureId);
1508            }
1509    
1510            public List<JournalArticle> getStructureArticles(
1511                            long groupId, String structureId, int start, int end,
1512                            OrderByComparator obc)
1513                    throws SystemException {
1514    
1515                    return journalArticlePersistence.findByG_S(
1516                            groupId, structureId, start, end, obc);
1517            }
1518    
1519            public int getStructureArticlesCount(long groupId, String structureId)
1520                    throws SystemException {
1521    
1522                    return journalArticlePersistence.countByG_S(groupId, structureId);
1523            }
1524    
1525            public List<JournalArticle> getTemplateArticles(
1526                            long groupId, String templateId)
1527                    throws SystemException {
1528    
1529                    return journalArticlePersistence.findByG_T(groupId, templateId);
1530            }
1531    
1532            public List<JournalArticle> getTemplateArticles(
1533                            long groupId, String templateId, int start, int end,
1534                            OrderByComparator obc)
1535                    throws SystemException {
1536    
1537                    return journalArticlePersistence.findByG_T(
1538                            groupId, templateId, start, end, obc);
1539            }
1540    
1541            public int getTemplateArticlesCount(long groupId, String templateId)
1542                    throws SystemException {
1543    
1544                    return journalArticlePersistence.countByG_T(groupId, templateId);
1545            }
1546    
1547            public boolean hasArticle(long groupId, String articleId)
1548                    throws SystemException {
1549    
1550                    try {
1551                            getArticle(groupId, articleId);
1552    
1553                            return true;
1554                    }
1555                    catch (PortalException pe) {
1556                            return false;
1557                    }
1558            }
1559    
1560            public boolean isLatestVersion(
1561                            long groupId, String articleId, double version)
1562                    throws PortalException, SystemException {
1563    
1564                    if (getLatestVersion(groupId, articleId) == version) {
1565                            return true;
1566                    }
1567                    else {
1568                            return false;
1569                    }
1570            }
1571    
1572            public boolean isLatestVersion(
1573                            long groupId, String articleId, double version, int status)
1574                    throws PortalException, SystemException {
1575    
1576                    if (getLatestVersion(groupId, articleId, status) == version) {
1577                            return true;
1578                    }
1579                    else {
1580                            return false;
1581                    }
1582            }
1583    
1584            public JournalArticle removeArticleLocale(
1585                            long groupId, String articleId, double version, String languageId)
1586                    throws PortalException, SystemException {
1587    
1588                    JournalArticle article = journalArticlePersistence.findByG_A_V(
1589                            groupId, articleId, version);
1590    
1591                    String title = article.getTitle();
1592    
1593                    title = LocalizationUtil.removeLocalization(
1594                            title, "static-content", languageId, true);
1595    
1596                    article.setTitle(title);
1597    
1598                    String description = article.getDescription();
1599    
1600                    description = LocalizationUtil.removeLocalization(
1601                            description, "static-content", languageId, true);
1602    
1603                    article.setDescription(description);
1604    
1605                    String content = article.getContent();
1606    
1607                    if (article.isTemplateDriven()) {
1608                            content = JournalUtil.removeArticleLocale(content, languageId);
1609                    }
1610                    else {
1611                            content = LocalizationUtil.removeLocalization(
1612                                    content, "static-content", languageId, true);
1613                    }
1614    
1615                    article.setContent(content);
1616    
1617                    journalArticlePersistence.update(article, false);
1618    
1619                    return article;
1620            }
1621    
1622            public List<JournalArticle> search(
1623                            long companyId, long groupId, long classNameId, String keywords,
1624                            Double version, String type, String structureId, String templateId,
1625                            Date displayDateGT, Date displayDateLT, int status, Date reviewDate,
1626                            int start, int end, OrderByComparator obc)
1627                    throws SystemException {
1628    
1629                    return journalArticleFinder.findByKeywords(
1630                            companyId, groupId, classNameId, keywords, version, type,
1631                            structureId, templateId, displayDateGT, displayDateLT, status,
1632                            reviewDate, start, end, obc);
1633            }
1634    
1635            public List<JournalArticle> search(
1636                            long companyId, long groupId, long classNameId, String articleId,
1637                            Double version, String title, String description, String content,
1638                            String type, String structureId, String templateId,
1639                            Date displayDateGT, Date displayDateLT, int status, Date reviewDate,
1640                            boolean andOperator, int start, int end, OrderByComparator obc)
1641                    throws SystemException {
1642    
1643                    return journalArticleFinder.findByC_G_C_A_V_T_D_C_T_S_T_D_S_R(
1644                            companyId, groupId, classNameId, articleId, version, title,
1645                            description, content, type, structureId, templateId, displayDateGT,
1646                            displayDateLT, status, reviewDate, andOperator, start, end, obc);
1647            }
1648    
1649            public List<JournalArticle> search(
1650                            long companyId, long groupId, long classNameId, String articleId,
1651                            Double version, String title, String description, String content,
1652                            String type, String[] structureIds, String[] templateIds,
1653                            Date displayDateGT, Date displayDateLT, int status, Date reviewDate,
1654                            boolean andOperator, int start, int end, OrderByComparator obc)
1655                    throws SystemException {
1656    
1657                    return journalArticleFinder.findByC_G_C_A_V_T_D_C_T_S_T_D_S_R(
1658                            companyId, groupId, classNameId, articleId, version, title,
1659                            description, content, type, structureIds, templateIds,
1660                            displayDateGT, displayDateLT, status, reviewDate, andOperator,
1661                            start, end, obc);
1662            }
1663    
1664            public Hits search(
1665                            long companyId, long groupId, long classNameId, String structureId,
1666                            String templateId, String keywords,
1667                            LinkedHashMap<String, Object> params, int start, int end, Sort sort)
1668                    throws SystemException {
1669    
1670                    String articleId = null;
1671                    String title = null;
1672                    String description = null;
1673                    String content = null;
1674                    boolean andOperator = false;
1675    
1676                    if (Validator.isNotNull(keywords)) {
1677                            articleId = keywords;
1678                            title = keywords;
1679                            description = keywords;
1680                            content = keywords;
1681                    }
1682                    else {
1683                            andOperator = true;
1684                    }
1685    
1686                    String status = String.valueOf(WorkflowConstants.STATUS_ANY);
1687    
1688                    if (params != null) {
1689                            params.put("keywords", keywords);
1690                    }
1691    
1692                    return search(
1693                            companyId, groupId, classNameId, articleId, title, description,
1694                            content, null, status, structureId, templateId, params, andOperator,
1695                            start, end, sort);
1696            }
1697    
1698            public Hits search(
1699                            long companyId, long groupId, long classNameId, String articleId,
1700                            String title, String description, String content, String type,
1701                            String status, String structureId, String templateId,
1702                            LinkedHashMap<String, Object> params, boolean andSearch, int start,
1703                            int end, Sort sort)
1704                    throws SystemException {
1705    
1706                    try {
1707                            SearchContext searchContext = new SearchContext();
1708    
1709                            searchContext.setAndSearch(andSearch);
1710    
1711                            Map<String, Serializable> attributes =
1712                                    new HashMap<String, Serializable>();
1713    
1714                            attributes.put(Field.CLASS_NAME_ID, classNameId);
1715                            attributes.put(Field.CONTENT, content);
1716                            attributes.put(Field.DESCRIPTION, description);
1717                            attributes.put(Field.STATUS, status);
1718                            attributes.put(Field.TITLE, title);
1719                            attributes.put(Field.TYPE, type);
1720                            attributes.put("articleId", articleId);
1721                            attributes.put("params", params);
1722                            attributes.put("structureId", structureId);
1723                            attributes.put("templateId", templateId);
1724    
1725                            searchContext.setAttributes(attributes);
1726    
1727                            searchContext.setCompanyId(companyId);
1728                            searchContext.setEnd(end);
1729                            searchContext.setGroupIds(new long[] {groupId});
1730    
1731                            if (params != null) {
1732                                    String keywords = (String)params.remove("keywords");
1733    
1734                                    if (Validator.isNotNull(keywords)) {
1735                                            searchContext.setKeywords(keywords);
1736                                    }
1737                            }
1738    
1739                            QueryConfig queryConfig = new QueryConfig();
1740    
1741                            queryConfig.setHighlightEnabled(false);
1742                            queryConfig.setScoreEnabled(false);
1743    
1744                            searchContext.setQueryConfig(queryConfig);
1745    
1746                            searchContext.setSorts(new Sort[] {sort});
1747                            searchContext.setStart(start);
1748    
1749                            Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
1750                                    JournalArticle.class);
1751    
1752                            return indexer.search(searchContext);
1753                    }
1754                    catch (Exception e) {
1755                            throw new SystemException(e);
1756                    }
1757            }
1758    
1759            public int searchCount(
1760                            long companyId, long groupId, long classNameId, String keywords,
1761                            Double version, String type, String structureId, String templateId,
1762                            Date displayDateGT, Date displayDateLT, int status, Date reviewDate)
1763                    throws SystemException {
1764    
1765                    return journalArticleFinder.countByKeywords(
1766                            companyId, groupId, classNameId, keywords, version, type,
1767                            structureId, templateId, displayDateGT, displayDateLT, status,
1768                            reviewDate);
1769            }
1770    
1771            public int searchCount(
1772                            long companyId, long groupId, long classNameId, String articleId,
1773                            Double version, String title, String description, String content,
1774                            String type, String structureId, String templateId,
1775                            Date displayDateGT, Date displayDateLT, int status, Date reviewDate,
1776                            boolean andOperator)
1777                    throws SystemException {
1778    
1779                    return journalArticleFinder.countByC_G_C_A_V_T_D_C_T_S_T_D_S_R(
1780                            companyId, groupId, classNameId, articleId, version, title,
1781                            description, content, type, structureId, templateId, displayDateGT,
1782                            displayDateLT, status, reviewDate, andOperator);
1783            }
1784    
1785            public int searchCount(
1786                            long companyId, long groupId, long classNameId, String articleId,
1787                            Double version, String title, String description, String content,
1788                            String type, String[] structureIds, String[] templateIds,
1789                            Date displayDateGT, Date displayDateLT, int status, Date reviewDate,
1790                            boolean andOperator)
1791                    throws SystemException {
1792    
1793                    return journalArticleFinder.countByC_G_C_A_V_T_D_C_T_S_T_D_S_R(
1794                            companyId, groupId, classNameId, articleId, version, title,
1795                            description, content, type, structureIds, templateIds,
1796                            displayDateGT, displayDateLT, status, reviewDate, andOperator);
1797            }
1798    
1799            public void subscribe(long userId, long groupId)
1800                    throws PortalException, SystemException {
1801    
1802                    subscriptionLocalService.addSubscription(
1803                            userId, groupId, JournalArticle.class.getName(), groupId);
1804            }
1805    
1806            public void unsubscribe(long userId, long groupId)
1807                    throws PortalException, SystemException {
1808    
1809                    subscriptionLocalService.deleteSubscription(
1810                            userId, JournalArticle.class.getName(), groupId);
1811            }
1812    
1813            public JournalArticle updateArticle(
1814                            long userId, long groupId, String articleId, double version,
1815                            Map<Locale, String> titleMap, Map<Locale, String> descriptionMap,
1816                            String content, String layoutUuid, ServiceContext serviceContext)
1817                    throws PortalException, SystemException {
1818    
1819                    User user = userPersistence.findByPrimaryKey(userId);
1820    
1821                    JournalArticle article = journalArticlePersistence.findByG_A_V(
1822                            groupId, articleId, version);
1823    
1824                    Date displayDate = article.getDisplayDate();
1825    
1826                    int displayDateMonth = 0;
1827                    int displayDateDay = 0;
1828                    int displayDateYear = 0;
1829                    int displayDateHour = 0;
1830                    int displayDateMinute = 0;
1831    
1832                    if (displayDate != null) {
1833                            Calendar displayCal = CalendarFactoryUtil.getCalendar(
1834                                    user.getTimeZone());
1835    
1836                            displayCal.setTime(displayDate);
1837    
1838                            displayDateMonth = displayCal.get(Calendar.MONTH);
1839                            displayDateDay = displayCal.get(Calendar.DATE);
1840                            displayDateYear = displayCal.get(Calendar.YEAR);
1841                            displayDateHour = displayCal.get(Calendar.HOUR);
1842                            displayDateMinute = displayCal.get(Calendar.MINUTE);
1843    
1844                            if (displayCal.get(Calendar.AM_PM) == Calendar.PM) {
1845                                    displayDateHour += 12;
1846                            }
1847                    }
1848    
1849                    Date expirationDate = article.getExpirationDate();
1850    
1851                    int expirationDateMonth = 0;
1852                    int expirationDateDay = 0;
1853                    int expirationDateYear = 0;
1854                    int expirationDateHour = 0;
1855                    int expirationDateMinute = 0;
1856                    boolean neverExpire = true;
1857    
1858                    if (expirationDate != null) {
1859                            Calendar expirationCal = CalendarFactoryUtil.getCalendar(
1860                                    user.getTimeZone());
1861    
1862                            expirationCal.setTime(expirationDate);
1863    
1864                            expirationDateMonth = expirationCal.get(Calendar.MONTH);
1865                            expirationDateDay = expirationCal.get(Calendar.DATE);
1866                            expirationDateYear = expirationCal.get(Calendar.YEAR);
1867                            expirationDateHour = expirationCal.get(Calendar.HOUR);
1868                            expirationDateMinute = expirationCal.get(Calendar.MINUTE);
1869                            neverExpire = false;
1870    
1871                            if (expirationCal.get(Calendar.AM_PM) == Calendar.PM) {
1872                                    expirationDateHour += 12;
1873                            }
1874                    }
1875    
1876                    Date reviewDate = article.getReviewDate();
1877    
1878                    int reviewDateMonth = 0;
1879                    int reviewDateDay = 0;
1880                    int reviewDateYear = 0;
1881                    int reviewDateHour = 0;
1882                    int reviewDateMinute = 0;
1883                    boolean neverReview = true;
1884    
1885                    if (reviewDate != null) {
1886                            Calendar reviewCal = CalendarFactoryUtil.getCalendar(
1887                                    user.getTimeZone());
1888    
1889                            reviewCal.setTime(reviewDate);
1890    
1891                            reviewDateMonth = reviewCal.get(Calendar.MONTH);
1892                            reviewDateDay = reviewCal.get(Calendar.DATE);
1893                            reviewDateYear = reviewCal.get(Calendar.YEAR);
1894                            reviewDateHour = reviewCal.get(Calendar.HOUR);
1895                            reviewDateMinute = reviewCal.get(Calendar.MINUTE);
1896                            neverReview = false;
1897    
1898                            if (reviewCal.get(Calendar.AM_PM) == Calendar.PM) {
1899                                    reviewDateHour += 12;
1900                            }
1901                    }
1902    
1903                    return updateArticle(
1904                            userId, groupId, articleId, version, titleMap, descriptionMap,
1905                            content, article.getType(), article.getStructureId(),
1906                            article.getTemplateId(), layoutUuid, displayDateMonth,
1907                            displayDateDay, displayDateYear, displayDateHour, displayDateMinute,
1908                            expirationDateMonth, expirationDateDay, expirationDateYear,
1909                            expirationDateHour, expirationDateMinute, neverExpire,
1910                            reviewDateMonth, reviewDateDay, reviewDateYear, reviewDateHour,
1911                            reviewDateMinute, neverReview, article.getIndexable(),
1912                            article.isSmallImage(), article.getSmallImageURL(), null, null,
1913                            null, serviceContext);
1914            }
1915    
1916            public JournalArticle updateArticle(
1917                            long userId, long groupId, String articleId, double version,
1918                            Map<Locale, String> titleMap, Map<Locale, String> descriptionMap,
1919                            String content, String type, String structureId, String templateId,
1920                            String layoutUuid, int displayDateMonth, int displayDateDay,
1921                            int displayDateYear, int displayDateHour, int displayDateMinute,
1922                            int expirationDateMonth, int expirationDateDay,
1923                            int expirationDateYear, int expirationDateHour,
1924                            int expirationDateMinute, boolean neverExpire, int reviewDateMonth,
1925                            int reviewDateDay, int reviewDateYear, int reviewDateHour,
1926                            int reviewDateMinute, boolean neverReview, boolean indexable,
1927                            boolean smallImage, String smallImageURL, File smallImageFile,
1928                            Map<String, byte[]> images, String articleURL,
1929                            ServiceContext serviceContext)
1930                    throws PortalException, SystemException {
1931    
1932                    // Article
1933    
1934                    User user = userPersistence.findByPrimaryKey(userId);
1935                    articleId = articleId.trim().toUpperCase();
1936    
1937                    Date displayDate = PortalUtil.getDate(
1938                            displayDateMonth, displayDateDay, displayDateYear, displayDateHour,
1939                            displayDateMinute, user.getTimeZone(),
1940                            ArticleDisplayDateException.class);
1941    
1942                    Date expirationDate = null;
1943    
1944                    if (!neverExpire) {
1945                            expirationDate = PortalUtil.getDate(
1946                                    expirationDateMonth, expirationDateDay, expirationDateYear,
1947                                    expirationDateHour, expirationDateMinute, user.getTimeZone(),
1948                                    ArticleExpirationDateException.class);
1949                    }
1950    
1951                    Date now = new Date();
1952    
1953                    boolean expired = false;
1954    
1955                    if ((expirationDate != null) && expirationDate.before(now)) {
1956                            expired = true;
1957                    }
1958    
1959                    Date reviewDate = null;
1960    
1961                    if (!neverReview) {
1962                            reviewDate = PortalUtil.getDate(
1963                                    reviewDateMonth, reviewDateDay, reviewDateYear, reviewDateHour,
1964                                    reviewDateMinute, user.getTimeZone(),
1965                                    ArticleReviewDateException.class);
1966                    }
1967    
1968                    byte[] smallImageBytes = null;
1969    
1970                    try {
1971                            smallImageBytes = FileUtil.getBytes(smallImageFile);
1972                    }
1973                    catch (IOException ioe) {
1974                    }
1975    
1976                    JournalArticle oldArticle = null;
1977                    double oldVersion = 0;
1978    
1979                    boolean incrementVersion = false;
1980    
1981                    boolean imported = ParamUtil.getBoolean(serviceContext, "imported");
1982    
1983                    if (imported) {
1984                            oldArticle = getArticle(groupId, articleId, version);
1985                            oldVersion = version;
1986    
1987                            if (expired) {
1988                                    return expireArticle(
1989                                            userId, groupId, articleId, version, articleURL,
1990                                            serviceContext);
1991                            }
1992                    }
1993                    else {
1994                            oldArticle = getLatestArticle(
1995                                    groupId, articleId, WorkflowConstants.STATUS_ANY);
1996    
1997                            oldVersion = oldArticle.getVersion();
1998    
1999                            if ((version > 0) && (version != oldVersion)) {
2000                                    throw new ArticleVersionException();
2001                            }
2002    
2003                            serviceContext.validateModifiedDate(
2004                                    oldArticle, ArticleVersionException.class);
2005    
2006                            if (oldArticle.isApproved() || oldArticle.isExpired()) {
2007                                    incrementVersion = true;
2008                            }
2009                    }
2010    
2011                    validate(
2012                            user.getCompanyId(), groupId, oldArticle.getClassNameId(), titleMap,
2013                            content, type, structureId, templateId, smallImage, smallImageURL,
2014                            smallImageFile, smallImageBytes);
2015    
2016                    JournalArticle article = null;
2017    
2018                    if (incrementVersion) {
2019                            double newVersion = MathUtil.format(oldVersion + 0.1, 1, 1);
2020    
2021                            long id = counterLocalService.increment();
2022    
2023                            article = journalArticlePersistence.create(id);
2024    
2025                            article.setResourcePrimKey(oldArticle.getResourcePrimKey());
2026                            article.setGroupId(oldArticle.getGroupId());
2027                            article.setCompanyId(oldArticle.getCompanyId());
2028                            article.setUserId(user.getUserId());
2029                            article.setUserName(user.getFullName());
2030                            article.setCreateDate(serviceContext.getModifiedDate(now));
2031                            article.setClassNameId(oldArticle.getClassNameId());
2032                            article.setClassPK(oldArticle.getClassPK());
2033                            article.setArticleId(articleId);
2034                            article.setVersion(newVersion);
2035                            article.setSmallImageId(oldArticle.getSmallImageId());
2036                    }
2037                    else {
2038                            article = oldArticle;
2039                    }
2040    
2041                    Locale locale = LocaleUtil.getDefault();
2042    
2043                    String defaultLanguageId = ParamUtil.getString(
2044                            serviceContext, "defaultLanguageId");
2045    
2046                    if (Validator.isNull(defaultLanguageId)) {
2047                            defaultLanguageId = LocalizationUtil.getDefaultLocale(content);
2048                    }
2049    
2050                    if (Validator.isNotNull(defaultLanguageId)) {
2051                            locale = LocaleUtil.fromLanguageId(defaultLanguageId);
2052                    }
2053    
2054                    String title = titleMap.get(locale);
2055    
2056                    content = format(
2057                            user, groupId, articleId, article.getVersion(), incrementVersion,
2058                            content, structureId, images);
2059    
2060                    article.setModifiedDate(serviceContext.getModifiedDate(now));
2061                    article.setTitleMap(titleMap, locale);
2062                    article.setUrlTitle(
2063                            getUniqueUrlTitle(
2064                                    article.getId(), article.getArticleId(), title,
2065                                    oldArticle.getUrlTitle(), serviceContext));
2066                    article.setDescriptionMap(descriptionMap, locale);
2067                    article.setContent(content);
2068                    article.setType(type);
2069                    article.setStructureId(structureId);
2070                    article.setTemplateId(templateId);
2071                    article.setLayoutUuid(layoutUuid);
2072                    article.setDisplayDate(displayDate);
2073                    article.setExpirationDate(expirationDate);
2074                    article.setReviewDate(reviewDate);
2075                    article.setIndexable(indexable);
2076                    article.setSmallImage(smallImage);
2077    
2078                    if (article.getSmallImageId() == 0) {
2079                            article.setSmallImageId(counterLocalService.increment());
2080                    }
2081    
2082                    article.setSmallImageURL(smallImageURL);
2083    
2084                    if (oldArticle.isPending()) {
2085                            article.setStatus(oldArticle.getStatus());
2086                    }
2087                    else if (!expired) {
2088                            article.setStatus(WorkflowConstants.STATUS_DRAFT);
2089                    }
2090                    else {
2091                            article.setStatus(WorkflowConstants.STATUS_EXPIRED);
2092                    }
2093    
2094                    journalArticlePersistence.update(article, false);
2095    
2096                    // Asset
2097    
2098                    updateAsset(
2099                            userId, article, serviceContext.getAssetCategoryIds(),
2100                            serviceContext.getAssetTagNames(),
2101                            serviceContext.getAssetLinkEntryIds());
2102    
2103                    // Expando
2104    
2105                    ExpandoBridge expandoBridge = article.getExpandoBridge();
2106    
2107                    expandoBridge.setAttributes(serviceContext);
2108    
2109                    // Small image
2110    
2111                    saveImages(
2112                            smallImage, article.getSmallImageId(), smallImageFile,
2113                            smallImageBytes);
2114    
2115                    // Email
2116    
2117                    PortletPreferences preferences =
2118                            ServiceContextUtil.getPortletPreferences(serviceContext);
2119    
2120                    // Workflow
2121    
2122                    if (serviceContext.getWorkflowAction() ==
2123                                    WorkflowConstants.ACTION_PUBLISH) {
2124    
2125                            sendEmail(
2126                                    article, articleURL, preferences, "requested", serviceContext);
2127    
2128                            WorkflowHandlerRegistryUtil.startWorkflowInstance(
2129                                    user.getCompanyId(), groupId, userId,
2130                                    JournalArticle.class.getName(), article.getId(), article,
2131                                    serviceContext);
2132                    }
2133                    else if (article.getVersion() ==
2134                                            JournalArticleConstants.VERSION_DEFAULT) {
2135    
2136                            // Indexer
2137    
2138                            Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
2139                                    JournalArticle.class);
2140    
2141                            indexer.reindex(article);
2142                    }
2143    
2144                    return article;
2145            }
2146    
2147            public JournalArticle updateArticle(
2148                            long userId, long groupId, String articleId, double version,
2149                            String content, ServiceContext serviceContext)
2150                    throws PortalException, SystemException {
2151    
2152                    JournalArticle article = journalArticlePersistence.findByG_A_V(
2153                            groupId, articleId, version);
2154    
2155                    return updateArticle(
2156                            userId, groupId, articleId, version, article.getTitleMap(),
2157                            article.getDescriptionMap(), content, article.getLayoutUuid(),
2158                            serviceContext);
2159            }
2160    
2161            /**
2162             * @deprecated {@link #updateArticleTranslation(long, String, double,
2163             *             Locale, String, String, String, Map, ServiceContext)}
2164             */
2165            public JournalArticle updateArticleTranslation(
2166                            long groupId, String articleId, double version, Locale locale,
2167                            String title, String description, String content,
2168                            Map<String, byte[]> images)
2169                    throws PortalException, SystemException {
2170    
2171                    return updateArticleTranslation(
2172                            groupId, articleId, version, locale, title, description, content,
2173                            images, null);
2174            }
2175    
2176            public JournalArticle updateArticleTranslation(
2177                            long groupId, String articleId, double version, Locale locale,
2178                            String title, String description, String content,
2179                            Map<String, byte[]> images, ServiceContext serviceContext)
2180                    throws PortalException, SystemException {
2181    
2182                    validateContent(content);
2183    
2184                    JournalArticle oldArticle = getLatestArticle(
2185                            groupId, articleId, WorkflowConstants.STATUS_ANY);
2186    
2187                    double oldVersion = oldArticle.getVersion();
2188    
2189                    if ((version > 0) && (version != oldVersion)) {
2190                            throw new ArticleVersionException();
2191                    }
2192    
2193                    boolean incrementVersion = false;
2194    
2195                    if (oldArticle.isApproved() || oldArticle.isExpired()) {
2196                            incrementVersion = true;
2197                    }
2198    
2199                    if (serviceContext != null) {
2200                            serviceContext.validateModifiedDate(
2201                                    oldArticle, ArticleVersionException.class);
2202                    }
2203    
2204                    JournalArticle article = null;
2205    
2206                    User user = userPersistence.findByPrimaryKey(oldArticle.getUserId());
2207    
2208                    if (incrementVersion) {
2209                            double newVersion = MathUtil.format(oldVersion + 0.1, 1, 1);
2210    
2211                            long id = counterLocalService.increment();
2212    
2213                            article = journalArticlePersistence.create(id);
2214    
2215                            article.setResourcePrimKey(oldArticle.getResourcePrimKey());
2216                            article.setGroupId(oldArticle.getGroupId());
2217                            article.setCompanyId(oldArticle.getCompanyId());
2218                            article.setUserId(oldArticle.getUserId());
2219                            article.setUserName(user.getFullName());
2220                            article.setCreateDate(new Date());
2221                            article.setModifiedDate(new Date());
2222                            article.setClassNameId(oldArticle.getClassNameId());
2223                            article.setClassPK(oldArticle.getClassPK());
2224                            article.setArticleId(articleId);
2225                            article.setVersion(newVersion);
2226                            article.setTitleMap(oldArticle.getTitleMap());
2227                            article.setUrlTitle(
2228                                    getUniqueUrlTitle(
2229                                            id, articleId, title, oldArticle.getUrlTitle(),
2230                                            serviceContext));
2231                            article.setDescriptionMap(oldArticle.getDescriptionMap());
2232                            article.setType(oldArticle.getType());
2233                            article.setStructureId(oldArticle.getStructureId());
2234                            article.setTemplateId(oldArticle.getTemplateId());
2235                            article.setLayoutUuid(oldArticle.getLayoutUuid());
2236                            article.setDisplayDate(oldArticle.getDisplayDate());
2237                            article.setExpirationDate(oldArticle.getExpirationDate());
2238                            article.setReviewDate(oldArticle.getReviewDate());
2239                            article.setIndexable(oldArticle.getIndexable());
2240                            article.setSmallImage(oldArticle.getSmallImage());
2241                            article.setSmallImageId(oldArticle.getSmallImageId());
2242    
2243                            if (article.getSmallImageId() == 0) {
2244                                    article.setSmallImageId(counterLocalService.increment());
2245                            }
2246    
2247                            article.setSmallImageURL(oldArticle.getSmallImageURL());
2248    
2249                            article.setStatus(WorkflowConstants.STATUS_DRAFT);
2250                            article.setStatusDate(new Date());
2251                    }
2252                    else {
2253                            article = oldArticle;
2254                    }
2255    
2256                    Map<Locale, String> titleMap = article.getTitleMap();
2257    
2258                    titleMap.put(locale, title);
2259    
2260                    article.setTitleMap(titleMap);
2261    
2262                    Map<Locale, String> descriptionMap = article.getDescriptionMap();
2263    
2264                    descriptionMap.put(locale, description);
2265    
2266                    article.setDescriptionMap(descriptionMap);
2267    
2268                    content = format(
2269                            user, groupId, articleId, article.getVersion(),
2270                            !oldArticle.isDraft(), content, oldArticle.getStructureId(),
2271                            images);
2272    
2273                    article.setContent(content);
2274    
2275                    journalArticlePersistence.update(article, false);
2276    
2277                    return article;
2278            }
2279    
2280            public void updateAsset(
2281                            long userId, JournalArticle article, long[] assetCategoryIds,
2282                            String[] assetTagNames, long[] assetLinkEntryIds)
2283                    throws PortalException, SystemException {
2284    
2285                    boolean visible = article.isApproved();
2286    
2287                    if (article.getClassNameId() > 0) {
2288                            visible = false;
2289                    }
2290    
2291                    boolean addDraftAssetEntry = false;
2292    
2293                    if (!article.isApproved() &&
2294                            (article.getVersion() != JournalArticleConstants.VERSION_DEFAULT)) {
2295    
2296                            int approvedArticlesCount = journalArticlePersistence.countByG_A_ST(
2297                                    article.getGroupId(), article.getArticleId(),
2298                                    JournalArticleConstants.ASSET_ENTRY_CREATION_STATUSES);
2299    
2300                            if (approvedArticlesCount > 0) {
2301                                    addDraftAssetEntry = true;
2302                            }
2303                    }
2304    
2305                    AssetEntry assetEntry = null;
2306    
2307                    if (addDraftAssetEntry) {
2308                            assetEntry = assetEntryLocalService.updateEntry(
2309                                    userId, article.getGroupId(), JournalArticle.class.getName(),
2310                                    article.getPrimaryKey(), article.getUuid(),
2311                                    getClassTypeId(article), assetCategoryIds, assetTagNames, false,
2312                                    null, null, article.getDisplayDate(),
2313                                    article.getExpirationDate(), ContentTypes.TEXT_HTML,
2314                                    article.getTitle(), article.getDescription(),
2315                                    article.getDescription(), null, article.getLayoutUuid(), 0, 0,
2316                                    null, false);
2317                    }
2318                    else {
2319    
2320                            // Get the earliest display date and latest expiration date among
2321                            // all article versions
2322    
2323                            Date[] dateInterval = getDateInterval(
2324                                    article.getGroupId(), article.getArticleId(),
2325                                    article.getDisplayDate(), article.getExpirationDate());
2326    
2327                            Date displayDate = dateInterval[0];
2328                            Date expirationDate = dateInterval[1];
2329    
2330                            JournalArticleResource journalArticleResource =
2331                                    journalArticleResourceLocalService.getArticleResource(
2332                                            article.getResourcePrimKey());
2333    
2334                            assetEntry = assetEntryLocalService.updateEntry(
2335                                    userId, article.getGroupId(), JournalArticle.class.getName(),
2336                                    journalArticleResource.getResourcePrimKey(),
2337                                    journalArticleResource.getUuid(), getClassTypeId(article),
2338                                    assetCategoryIds, assetTagNames, visible, null, null,
2339                                    displayDate, expirationDate, ContentTypes.TEXT_HTML,
2340                                    article.getTitle(), article.getDescription(),
2341                                    article.getDescription(), null, article.getLayoutUuid(), 0, 0,
2342                                    null, false);
2343                    }
2344    
2345                    assetLinkLocalService.updateLinks(
2346                            userId, assetEntry.getEntryId(), assetLinkEntryIds,
2347                            AssetLinkConstants.TYPE_RELATED);
2348            }
2349    
2350            public JournalArticle updateContent(
2351                            long groupId, String articleId, double version, String content)
2352                    throws PortalException, SystemException {
2353    
2354                    JournalArticle article = journalArticlePersistence.findByG_A_V(
2355                            groupId, articleId, version);
2356    
2357                    article.setContent(content);
2358    
2359                    journalArticlePersistence.update(article, false);
2360    
2361                    return article;
2362            }
2363    
2364            public JournalArticle updateStatus(
2365                            long userId, JournalArticle article, int status, String articleURL,
2366                            ServiceContext serviceContext)
2367                    throws PortalException, SystemException {
2368    
2369                    // Article
2370    
2371                    User user = userPersistence.findByPrimaryKey(userId);
2372                    Date now = new Date();
2373    
2374                    int oldStatus = article.getStatus();
2375    
2376                    article.setModifiedDate(serviceContext.getModifiedDate(now));
2377    
2378                    boolean neverExpire = false;
2379    
2380                    if (status == WorkflowConstants.STATUS_APPROVED) {
2381                            Date expirationDate = article.getExpirationDate();
2382    
2383                            if ((expirationDate != null) && expirationDate.before(now)) {
2384                                    neverExpire = true;
2385    
2386                                    article.setExpirationDate(null);
2387                            }
2388                    }
2389    
2390                    if (status == WorkflowConstants.STATUS_EXPIRED) {
2391                            article.setExpirationDate(now);
2392                    }
2393    
2394                    article.setStatus(status);
2395                    article.setStatusByUserId(user.getUserId());
2396                    article.setStatusByUserName(user.getFullName());
2397                    article.setStatusDate(serviceContext.getModifiedDate(now));
2398    
2399                    journalArticlePersistence.update(article, false);
2400    
2401                    if (hasModifiedLatestApprovedVersion (
2402                                    article.getGroupId(), article.getArticleId(),
2403                                    article.getVersion())) {
2404    
2405                            if (status == WorkflowConstants.STATUS_APPROVED) {
2406                                    updateUrlTitles(
2407                                            article.getGroupId(), article.getArticleId(),
2408                                            article.getUrlTitle());
2409    
2410                                    // Asset
2411    
2412                                    if ((oldStatus != WorkflowConstants.STATUS_APPROVED) &&
2413                                            (article.getVersion() !=
2414                                                    JournalArticleConstants.VERSION_DEFAULT)) {
2415    
2416                                            AssetEntry draftAssetEntry = null;
2417    
2418                                            try {
2419                                                    draftAssetEntry = assetEntryLocalService.getEntry(
2420                                                            JournalArticle.class.getName(),
2421                                                            article.getPrimaryKey());
2422    
2423                                                    Date displayDate = draftAssetEntry.getPublishDate();
2424                                                    Date expirationDate =
2425                                                            draftAssetEntry.getExpirationDate();
2426    
2427                                                    long[] assetCategoryIds =
2428                                                            draftAssetEntry.getCategoryIds();
2429                                                    String[] assetTagNames = draftAssetEntry.getTagNames();
2430    
2431                                                    List<AssetLink> assetLinks =
2432                                                            assetLinkLocalService.getDirectLinks(
2433                                                                    draftAssetEntry.getEntryId(),
2434                                                                    AssetLinkConstants.TYPE_RELATED);
2435    
2436                                                    long[] assetLinkEntryIds = StringUtil.split(
2437                                                            ListUtil.toString(
2438                                                                    assetLinks, AssetLink.ENTRY_ID2_ACCESSOR), 0L);
2439    
2440                                                    boolean visible = true;
2441    
2442                                                    if (article.getClassNameId() > 0) {
2443                                                            visible = false;
2444                                                    }
2445    
2446                                                    AssetEntry assetEntry =
2447                                                            assetEntryLocalService.updateEntry(
2448                                                                    userId, article.getGroupId(),
2449                                                                    JournalArticle.class.getName(),
2450                                                                    article.getResourcePrimKey(), article.getUuid(),
2451                                                                    getClassTypeId(article), assetCategoryIds,
2452                                                                    assetTagNames, visible, null, null, displayDate,
2453                                                                    expirationDate, ContentTypes.TEXT_HTML,
2454                                                                    article.getTitle(), article.getDescription(),
2455                                                                    article.getDescription(), null,
2456                                                                    article.getLayoutUuid(), 0, 0, null, false);
2457    
2458                                                    assetLinkLocalService.updateLinks(
2459                                                            userId, assetEntry.getEntryId(), assetLinkEntryIds,
2460                                                            AssetLinkConstants.TYPE_RELATED);
2461    
2462                                                    assetEntryLocalService.deleteEntry(
2463                                                            JournalArticle.class.getName(),
2464                                                            article.getPrimaryKey());
2465                                            }
2466                                            catch (NoSuchEntryException nsee) {
2467                                            }
2468                                    }
2469    
2470                                    if (article.getClassNameId() == 0) {
2471                                            AssetEntry assetEntry =
2472                                                    assetEntryLocalService.updateVisible(
2473                                                            JournalArticle.class.getName(),
2474                                                            article.getResourcePrimKey(), true);
2475    
2476                                            if (neverExpire) {
2477                                                    assetEntry.setExpirationDate(null);
2478    
2479                                                    assetEntryLocalService.updateAssetEntry(
2480                                                            assetEntry, false);
2481                                            }
2482                                    }
2483    
2484                                    // Expando
2485    
2486                                    ExpandoBridge expandoBridge = article.getExpandoBridge();
2487    
2488                                    expandoBridge.setAttributes(serviceContext);
2489    
2490                                    // Indexer
2491    
2492                                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
2493                                            JournalArticle.class);
2494    
2495                                    indexer.reindex(article);
2496                            }
2497                            else if (oldStatus == WorkflowConstants.STATUS_APPROVED) {
2498                                    updatePreviousApprovedArticle(article);
2499                            }
2500                    }
2501    
2502                    if (article.getClassNameId() == 0) {
2503    
2504                            // Email
2505    
2506                            if ((oldStatus == WorkflowConstants.STATUS_PENDING) &&
2507                                    ((status == WorkflowConstants.STATUS_APPROVED) ||
2508                                     (status == WorkflowConstants.STATUS_DENIED))) {
2509    
2510                                    String msg = "granted";
2511    
2512                                    if (status == WorkflowConstants.STATUS_DENIED) {
2513                                            msg = "denied";
2514                                    }
2515    
2516                                    try {
2517                                            PortletPreferences preferences =
2518                                                    ServiceContextUtil.getPortletPreferences(
2519                                                            serviceContext);
2520    
2521                                            sendEmail(
2522                                                    article, articleURL, preferences, msg, serviceContext);
2523                                    }
2524                                    catch (Exception e) {
2525                                            _log.error(
2526                                                    "Unable to send email to notify the change of status " +
2527                                                            " to " + msg + " for article " + article.getId() +
2528                                                                    ": " + e.getMessage());
2529                                    }
2530                            }
2531    
2532                            // Subscriptions
2533    
2534                            notifySubscribers(article, serviceContext);
2535                    }
2536    
2537                    return article;
2538            }
2539    
2540            public JournalArticle updateStatus(
2541                            long userId, long classPK, int status,
2542                            ServiceContext serviceContext)
2543                    throws PortalException, SystemException {
2544    
2545                    JournalArticle article = getArticle(classPK);
2546    
2547                    return updateStatus(userId, article, status, null, serviceContext);
2548            }
2549    
2550            public JournalArticle updateStatus(
2551                            long userId, long groupId, String articleId, double version,
2552                            int status, String articleURL, ServiceContext serviceContext)
2553                    throws PortalException, SystemException {
2554    
2555                    JournalArticle article = journalArticlePersistence.findByG_A_V(
2556                            groupId, articleId, version);
2557    
2558                    return updateStatus(
2559                            userId, article, status, articleURL, serviceContext);
2560            }
2561    
2562            public void updateTemplateId(
2563                            long groupId, long classNameId, String oldTemplateId,
2564                            String newTemplateId)
2565                    throws SystemException {
2566    
2567                    List<JournalArticle> articles = journalArticlePersistence.findByG_C_T(
2568                            groupId, classNameId, oldTemplateId);
2569    
2570                    for (JournalArticle article : articles) {
2571                            article.setTemplateId(newTemplateId);
2572    
2573                            journalArticlePersistence.update(article, false);
2574                    }
2575            }
2576    
2577            protected void checkStructure(Document contentDoc, Element root)
2578                    throws PortalException {
2579    
2580                    for (Element el : root.elements()) {
2581                            checkStructureField(el, contentDoc);
2582    
2583                            checkStructure(contentDoc, el);
2584                    }
2585            }
2586    
2587            protected void checkStructure(JournalArticle article)
2588                    throws DocumentException, PortalException, SystemException {
2589    
2590                    Group companyGroup = groupLocalService.getCompanyGroup(
2591                            article.getCompanyId());
2592    
2593                    JournalStructure structure = null;
2594    
2595                    try {
2596                            structure = journalStructurePersistence.findByG_S(
2597                                    article.getGroupId(), article.getStructureId());
2598                    }
2599                    catch (NoSuchStructureException nsse) {
2600                            structure = journalStructurePersistence.findByG_S(
2601                                    companyGroup.getGroupId(), article.getStructureId());
2602                    }
2603    
2604                    String content = GetterUtil.getString(article.getContent());
2605    
2606                    Document contentDoc = SAXReaderUtil.read(content);
2607                    Document xsdDoc = SAXReaderUtil.read(structure.getXsd());
2608    
2609                    try {
2610                            checkStructure(contentDoc, xsdDoc.getRootElement());
2611                    }
2612                    catch (StructureXsdException sxsde) {
2613                            long groupId = article.getGroupId();
2614                            String articleId = article.getArticleId();
2615                            double version = article.getVersion();
2616    
2617                            if (_log.isWarnEnabled()) {
2618                                    _log.warn(
2619                                            "Article {groupId=" + groupId + ", articleId=" +
2620                                                    articleId + ", version=" + version +
2621                                                            "} has content that does not match its " +
2622                                                                    "structure: " + sxsde.getMessage());
2623                            }
2624                    }
2625            }
2626    
2627            protected void checkStructureField(Element el, Document contentDoc)
2628                    throws PortalException {
2629    
2630                    StringBuilder elPath = new StringBuilder();
2631    
2632                    elPath.append(el.attributeValue("name"));
2633    
2634                    Element elParent = el.getParent();
2635    
2636                    for (;;) {
2637                            if ((elParent == null) || elParent.getName().equals("root")) {
2638                                    break;
2639                            }
2640    
2641                            elPath.insert(
2642                                    0, elParent.attributeValue("name") + StringPool.COMMA);
2643    
2644                            elParent = elParent.getParent();
2645                    }
2646    
2647                    String[] elPathNames = StringUtil.split(elPath.toString());
2648    
2649                    Element contentEl = contentDoc.getRootElement();
2650    
2651                    for (String _elPathName : elPathNames) {
2652                            boolean foundEl = false;
2653    
2654                            for (Element tempEl : contentEl.elements()) {
2655                                    if (_elPathName.equals(
2656                                                    tempEl.attributeValue("name", StringPool.BLANK))) {
2657    
2658                                            contentEl = tempEl;
2659                                            foundEl = true;
2660    
2661                                            break;
2662                                    }
2663                            }
2664    
2665                            if (!foundEl) {
2666                                    String elType = contentEl.attributeValue(
2667                                            "type", StringPool.BLANK);
2668    
2669                                    if (!elType.equals("list") && !elType.equals("multi-list")) {
2670                                            throw new StructureXsdException(elPath.toString());
2671                                    }
2672    
2673                                    break;
2674                            }
2675                    }
2676            }
2677    
2678            protected void copyArticleImages(
2679                            JournalArticle oldArticle, JournalArticle newArticle)
2680                    throws Exception {
2681    
2682                    Document contentDoc = SAXReaderUtil.read(oldArticle.getContent());
2683    
2684                    XPath xPathSelector = SAXReaderUtil.createXPath(
2685                            "//dynamic-element[@type='image']");
2686    
2687                    List<Node> imageNodes = xPathSelector.selectNodes(contentDoc);
2688    
2689                    for (Node imageNode : imageNodes) {
2690                            Element imageEl = (Element)imageNode;
2691    
2692                            String instanceId = imageEl.attributeValue("instance-id");
2693                            String name = imageEl.attributeValue("name");
2694    
2695                            List<Element> dynamicContentEls = imageEl.elements(
2696                                    "dynamic-content");
2697    
2698                            for (Element dynamicContentEl : dynamicContentEls) {
2699                                    long imageId = GetterUtil.getLong(
2700                                            dynamicContentEl.attributeValue("id"));
2701                                    String languageId = dynamicContentEl.attributeValue(
2702                                            "language-id");
2703    
2704                                    Image oldImage = null;
2705    
2706                                    try {
2707                                            oldImage = imageLocalService.getImage(imageId);
2708                                    }
2709                                    catch (NoSuchImageException nsie) {
2710                                            continue;
2711                                    }
2712    
2713                                    imageId = journalArticleImageLocalService.getArticleImageId(
2714                                            newArticle.getGroupId(), newArticle.getArticleId(),
2715                                            newArticle.getVersion(), instanceId, name, languageId);
2716    
2717                                    imageLocalService.updateImage(imageId, oldImage.getTextObj());
2718    
2719                                    String elContent =
2720                                            "/image/journal/article?img_id=" + imageId + "&t=" +
2721                                                    WebServerServletTokenUtil.getToken(imageId);
2722    
2723                                    dynamicContentEl.setText(elContent);
2724                                    dynamicContentEl.addAttribute("id", String.valueOf(imageId));
2725                            }
2726                    }
2727    
2728                    newArticle.setContent(contentDoc.formattedString());
2729            }
2730    
2731            protected void format(
2732                            User user, long groupId, String articleId, double version,
2733                            boolean incrementVersion, Element root, Map<String, byte[]> images)
2734                    throws PortalException, SystemException {
2735    
2736                    for (Element element : root.elements()) {
2737                            String elInstanceId = element.attributeValue(
2738                                    "instance-id", StringPool.BLANK);
2739                            String elName = element.attributeValue("name", StringPool.BLANK);
2740                            String elType = element.attributeValue("type", StringPool.BLANK);
2741    
2742                            if (elType.equals("image")) {
2743                                    formatImage(
2744                                            groupId, articleId, version, incrementVersion, element,
2745                                            elInstanceId, elName, images);
2746                            }
2747                            else if (elType.equals("text_area") || elType.equals("text") ||
2748                                             elType.equals("text_box")) {
2749    
2750                                    List<Element> dynamicContentElements = element.elements(
2751                                            "dynamic-content");
2752    
2753                                    for (Element dynamicContentElement : dynamicContentElements) {
2754                                            String dynamicContent = dynamicContentElement.getText();
2755    
2756                                            if (Validator.isNotNull(dynamicContent)) {
2757                                                    dynamicContent = SanitizerUtil.sanitize(
2758                                                            user.getCompanyId(), groupId, user.getUserId(),
2759                                                            JournalArticle.class.getName(), 0,
2760                                                            ContentTypes.TEXT_HTML, dynamicContent);
2761    
2762                                                    dynamicContentElement.clearContent();
2763    
2764                                                    dynamicContentElement.addCDATA(dynamicContent);
2765                                            }
2766                                    }
2767                            }
2768    
2769                            format(
2770                                    user, groupId, articleId, version, incrementVersion, element,
2771                                    images);
2772                    }
2773            }
2774    
2775            protected String format(
2776                            User user, long groupId, String articleId, double version,
2777                            boolean incrementVersion, String content, String structureId,
2778                            Map<String, byte[]> images)
2779                    throws PortalException, SystemException {
2780    
2781                    Document document = null;
2782    
2783                    try {
2784                            document = SAXReaderUtil.read(content);
2785    
2786                            Element rootElement = document.getRootElement();
2787    
2788                            if (Validator.isNotNull(structureId)) {
2789                                    format(
2790                                            user, groupId, articleId, version, incrementVersion,
2791                                            rootElement, images);
2792                            }
2793                            else {
2794                                    List<Element> staticContentElements = rootElement.elements(
2795                                            "static-content");
2796    
2797                                    for (Element staticContentElement : staticContentElements) {
2798                                            String staticContent = staticContentElement.getText();
2799    
2800                                            staticContent = SanitizerUtil.sanitize(
2801                                                    user.getCompanyId(), groupId, user.getUserId(),
2802                                                    JournalArticle.class.getName(), 0,
2803                                                    ContentTypes.TEXT_HTML, staticContent);
2804    
2805                                            staticContentElement.clearContent();
2806    
2807                                            staticContentElement.addCDATA(staticContent);
2808                                    }
2809                            }
2810    
2811                            content = DDMXMLUtil.formatXML(document);
2812                    }
2813                    catch (DocumentException de) {
2814                            _log.error(de);
2815                    }
2816                    catch (IOException ioe) {
2817                            _log.error(ioe);
2818                    }
2819    
2820                    content = HtmlUtil.replaceMsWordCharacters(content);
2821    
2822                    return content;
2823            }
2824    
2825            protected void formatImage(
2826                            long groupId, String articleId, double version,
2827                            boolean incrementVersion, Element el, String elInstanceId,
2828                            String elName, Map<String, byte[]> images)
2829                    throws PortalException, SystemException {
2830    
2831                    List<Element> imageContents = el.elements("dynamic-content");
2832    
2833                    for (Element dynamicContent : imageContents) {
2834                            String elLanguage = dynamicContent.attributeValue(
2835                                    "language-id", StringPool.BLANK);
2836    
2837                            if (!elLanguage.equals(StringPool.BLANK)) {
2838                                    elLanguage = "_" + elLanguage;
2839                            }
2840    
2841                            long imageId = journalArticleImageLocalService.getArticleImageId(
2842                                    groupId, articleId, version, elInstanceId, elName, elLanguage);
2843    
2844                            double oldVersion = MathUtil.format(version - 0.1, 1, 1);
2845    
2846                            long oldImageId = 0;
2847    
2848                            if ((oldVersion >= 1) && incrementVersion) {
2849                                    oldImageId = journalArticleImageLocalService.getArticleImageId(
2850                                            groupId, articleId, oldVersion, elInstanceId, elName,
2851                                            elLanguage);
2852                            }
2853    
2854                            String elContent =
2855                                    "/image/journal/article?img_id=" + imageId + "&t=" +
2856                                            WebServerServletTokenUtil.getToken(imageId);
2857    
2858                            if (dynamicContent.getText().equals("delete")) {
2859                                    dynamicContent.setText(StringPool.BLANK);
2860    
2861                                    imageLocalService.deleteImage(imageId);
2862    
2863                                    String defaultElLanguage = "";
2864    
2865                                    if (!Validator.isNotNull(elLanguage)) {
2866                                            defaultElLanguage =
2867                                                    "_" + LocaleUtil.toLanguageId(LocaleUtil.getDefault());
2868                                    }
2869    
2870                                    long defaultImageId =
2871                                            journalArticleImageLocalService.getArticleImageId(
2872                                                    groupId, articleId, version, elInstanceId, elName,
2873                                                    defaultElLanguage);
2874    
2875                                    imageLocalService.deleteImage(defaultImageId);
2876    
2877                                    continue;
2878                            }
2879    
2880                            byte[] bytes = images.get(elInstanceId + "_" + elName + elLanguage);
2881    
2882                            if ((bytes != null) && (bytes.length > 0)) {
2883                                    dynamicContent.setText(elContent);
2884                                    dynamicContent.addAttribute("id", String.valueOf(imageId));
2885    
2886                                    imageLocalService.updateImage(imageId, bytes);
2887    
2888                                    continue;
2889                            }
2890    
2891                            if ((version > JournalArticleConstants.VERSION_DEFAULT) &&
2892                                    incrementVersion) {
2893    
2894                                    Image oldImage = null;
2895    
2896                                    if (oldImageId > 0) {
2897                                            oldImage = imageLocalService.getImage(oldImageId);
2898                                    }
2899    
2900                                    if (oldImage != null) {
2901                                            dynamicContent.setText(elContent);
2902                                            dynamicContent.addAttribute("id", String.valueOf(imageId));
2903    
2904                                            bytes = oldImage.getTextObj();
2905    
2906                                            imageLocalService.updateImage(imageId, bytes);
2907                                    }
2908    
2909                                    continue;
2910                            }
2911    
2912                            Image image = imageLocalService.getImage(imageId);
2913    
2914                            if (image != null) {
2915                                    dynamicContent.setText(elContent);
2916                                    dynamicContent.addAttribute("id", String.valueOf(imageId));
2917    
2918                                    continue;
2919                            }
2920    
2921                            long contentImageId = GetterUtil.getLong(HttpUtil.getParameter(
2922                                    dynamicContent.getText(), "img_id"));
2923    
2924                            if (contentImageId <= 0) {
2925                                    contentImageId = GetterUtil.getLong(HttpUtil.getParameter(
2926                                            dynamicContent.getText(), "img_id", false));
2927                            }
2928    
2929                            if (contentImageId > 0) {
2930                                    image = imageLocalService.getImage(contentImageId);
2931    
2932                                    if (image != null) {
2933                                            dynamicContent.addAttribute(
2934                                                    "id", String.valueOf(contentImageId));
2935    
2936                                            continue;
2937                                    }
2938                            }
2939    
2940                            String defaultElLanguage = "";
2941    
2942                            if (!Validator.isNotNull(elLanguage)) {
2943                                    defaultElLanguage =
2944                                            "_" + LocaleUtil.toLanguageId(LocaleUtil.getDefault());
2945                            }
2946    
2947                            long defaultImageId =
2948                                    journalArticleImageLocalService.getArticleImageId(
2949                                            groupId, articleId, version, elInstanceId, elName,
2950                                            defaultElLanguage);
2951    
2952                            Image defaultImage = imageLocalService.getImage(defaultImageId);
2953    
2954                            if (defaultImage != null) {
2955                                    dynamicContent.setText(elContent);
2956                                    dynamicContent.addAttribute(
2957                                            "id", String.valueOf(defaultImageId));
2958    
2959                                    bytes = defaultImage.getTextObj();
2960    
2961                                    imageLocalService.updateImage(defaultImageId, bytes);
2962    
2963                                    continue;
2964                            }
2965    
2966                            if (Validator.isNotNull(elLanguage)) {
2967                                    dynamicContent.setText(StringPool.BLANK);
2968                            }
2969                    }
2970            }
2971    
2972            protected long getClassTypeId(JournalArticle article) {
2973                    long classTypeId = 0;
2974    
2975                    try {
2976                            JournalStructure structure = journalStructurePersistence.fetchByG_S(
2977                                    article.getGroupId(), article.getStructureId());
2978    
2979                            if (structure == null) {
2980                                    Group companyGroup = groupLocalService.getCompanyGroup(
2981                                            article.getCompanyId());
2982    
2983                                    structure = journalStructurePersistence.fetchByG_S(
2984                                            companyGroup.getGroupId(), article.getStructureId());
2985                            }
2986    
2987                            if (structure != null) {
2988                                    classTypeId = structure.getId();
2989                            }
2990                    }
2991                    catch (Exception e) {
2992                            _log.error(e, e);
2993                    }
2994    
2995                    return classTypeId;
2996            }
2997    
2998            protected Date[] getDateInterval(
2999                            long groupId, String articleId, Date earliestDisplayDate,
3000                            Date latestExpirationDate)
3001                    throws SystemException {
3002    
3003                    Date[] dateInterval = new Date[2];
3004    
3005                    List<JournalArticle> articles = journalArticlePersistence.findByG_A_ST(
3006                            groupId, articleId, WorkflowConstants.STATUS_APPROVED);
3007    
3008                    boolean expiringArticle = true;
3009    
3010                    if (latestExpirationDate == null) {
3011                            expiringArticle = false;
3012                    }
3013    
3014                    for (JournalArticle article : articles) {
3015                            if ((earliestDisplayDate == null) ||
3016                                    ((article.getDisplayDate() != null) &&
3017                                     earliestDisplayDate.after(article.getDisplayDate()))) {
3018    
3019                                    earliestDisplayDate = article.getDisplayDate();
3020                            }
3021    
3022                            if (expiringArticle &&
3023                                    ((latestExpirationDate == null) ||
3024                                     ((article.getExpirationDate() != null) &&
3025                                      latestExpirationDate.before(article.getExpirationDate())))) {
3026    
3027                                    latestExpirationDate = article.getExpirationDate();
3028                            }
3029    
3030                            if (expiringArticle && (article.getExpirationDate() == null) &&
3031                                    (latestExpirationDate != null)) {
3032    
3033                                    expiringArticle = false;
3034                            }
3035                    }
3036    
3037                    dateInterval[0] = earliestDisplayDate;
3038                    dateInterval[1] = latestExpirationDate;
3039    
3040                    return dateInterval;
3041            }
3042    
3043            protected String getUniqueUrlTitle(
3044                            long id, long groupId, String articleId, String title)
3045                    throws PortalException, SystemException {
3046    
3047                    String urlTitle = JournalUtil.getUrlTitle(id, title);
3048    
3049                    for (int i = 1;; i++) {
3050                            JournalArticle article = null;
3051    
3052                            try {
3053                                    article = getArticleByUrlTitle(groupId, urlTitle);
3054                            }
3055                            catch (NoSuchArticleException nsae) {
3056                            }
3057    
3058                            if ((article == null) || articleId.equals(article.getArticleId())) {
3059                                    break;
3060                            }
3061                            else {
3062                                    String suffix = StringPool.DASH + i;
3063    
3064                                    String prefix = urlTitle;
3065    
3066                                    if (urlTitle.length() > suffix.length()) {
3067                                            prefix = urlTitle.substring(
3068                                                    0, urlTitle.length() - suffix.length());
3069                                    }
3070    
3071                                    urlTitle = prefix + suffix;
3072                            }
3073                    }
3074    
3075                    return urlTitle;
3076            }
3077    
3078            protected String getUniqueUrlTitle(
3079                            long id, String articleId, String title, String oldUrlTitle,
3080                            ServiceContext serviceContext)
3081                    throws PortalException, SystemException {
3082    
3083                    String serviceContextUrlTitle = ParamUtil.getString(
3084                            serviceContext, "urlTitle");
3085    
3086                    String urlTitle = null;
3087    
3088                    if (isMatchesServiceContextUrlTitle(serviceContextUrlTitle)) {
3089                            urlTitle = JournalUtil.getUrlTitle(id, serviceContextUrlTitle);
3090    
3091                            JournalArticle urlTitleArticle = null;
3092    
3093                            try {
3094                                    urlTitleArticle = getArticleByUrlTitle(
3095                                            serviceContext.getScopeGroupId(), urlTitle);
3096                            }
3097                            catch (NoSuchArticleException nsae) {
3098                            }
3099    
3100                            if ((urlTitleArticle != null) &&
3101                                    !Validator.equals(
3102                                            urlTitleArticle.getArticleId(), articleId)) {
3103    
3104                                    urlTitle = getUniqueUrlTitle(
3105                                            id, serviceContext.getScopeGroupId(), articleId, urlTitle);
3106                            }
3107                    }
3108                    else {
3109                            if (isMatchesServiceContextUrlTitle(oldUrlTitle)) {
3110                                    urlTitle = oldUrlTitle;
3111                            }
3112                            else {
3113                                    urlTitle = getUniqueUrlTitle(
3114                                            id, serviceContext.getScopeGroupId(), articleId, title);
3115                            }
3116                    }
3117    
3118                    return urlTitle;
3119            }
3120    
3121            protected boolean hasModifiedLatestApprovedVersion(
3122                            long groupId, String articleId, double version)
3123                    throws PortalException, SystemException {
3124    
3125                    double latestApprovedVersion;
3126    
3127                    try {
3128                            latestApprovedVersion = getLatestVersion(
3129                                    groupId, articleId, WorkflowConstants.STATUS_APPROVED);
3130    
3131                            if (version >= latestApprovedVersion) {
3132                                    return true;
3133                            }
3134                            else {
3135                                    return false;
3136                            }
3137                    }
3138                    catch (NoSuchArticleException nsae) {
3139                            return true;
3140                    }
3141            }
3142    
3143            protected boolean isMatchesServiceContextUrlTitle(String urlTitle) {
3144                    if (Validator.isNotNull(urlTitle) &&
3145                            Validator.isNotNull(PropsValues.JOURNAL_ARTICLE_URL_TITLE_REGEXP)) {
3146    
3147                            Pattern pattern = Pattern.compile(
3148                                    PropsValues.JOURNAL_ARTICLE_URL_TITLE_REGEXP);
3149    
3150                            Matcher matcher = pattern.matcher(urlTitle);
3151    
3152                            return matcher.matches();
3153                    }
3154    
3155                    return false;
3156            }
3157    
3158            protected void notifySubscribers(
3159                            JournalArticle article, ServiceContext serviceContext)
3160                    throws PortalException, SystemException {
3161    
3162                    if (!article.isApproved()) {
3163                            return;
3164                    }
3165    
3166                    String articleURL = PortalUtil.getControlPanelFullURL(
3167                            serviceContext.getScopeGroupId(), PortletKeys.JOURNAL, null);
3168    
3169                    if (Validator.isNull(articleURL)) {
3170                            return;
3171                    }
3172    
3173                    PortletPreferences preferences =
3174                            ServiceContextUtil.getPortletPreferences(serviceContext);
3175    
3176                    if (preferences == null) {
3177                            long ownerId = article.getGroupId();
3178                            int ownerType = PortletKeys.PREFS_OWNER_TYPE_GROUP;
3179                            long plid = PortletKeys.PREFS_PLID_SHARED;
3180                            String portletId = PortletKeys.JOURNAL;
3181                            String defaultPreferences = null;
3182    
3183                            preferences = portletPreferencesLocalService.getPreferences(
3184                                    article.getCompanyId(), ownerId, ownerType, plid, portletId,
3185                                    defaultPreferences);
3186                    }
3187    
3188                    if ((article.getVersion() == 1.0) &&
3189                            JournalUtil.getEmailArticleAddedEnabled(preferences)) {
3190                    }
3191                    else if ((article.getVersion() != 1.0) &&
3192                                     JournalUtil.getEmailArticleUpdatedEnabled(preferences)) {
3193                    }
3194                    else {
3195                            return;
3196                    }
3197    
3198                    String fromName = JournalUtil.getEmailFromName(
3199                            preferences, article.getCompanyId());
3200                    String fromAddress = JournalUtil.getEmailFromAddress(
3201                            preferences, article.getCompanyId());
3202    
3203                    String subject = null;
3204                    String body = null;
3205    
3206                    if (article.getVersion() == 1.0) {
3207                            subject = JournalUtil.getEmailArticleAddedSubject(preferences);
3208                            body = JournalUtil.getEmailArticleAddedBody(preferences);
3209                    }
3210                    else {
3211                            subject = JournalUtil.getEmailArticleUpdatedSubject(preferences);
3212                            body = JournalUtil.getEmailArticleUpdatedBody(preferences);
3213                    }
3214    
3215                    SubscriptionSender subscriptionSender = new SubscriptionSender();
3216    
3217                    subscriptionSender.setBody(body);
3218                    subscriptionSender.setCompanyId(article.getCompanyId());
3219                    subscriptionSender.setContextAttributes(
3220                            "[$ARTICLE_ID$]", article.getArticleId(), "[$ARTICLE_TITLE$]",
3221                            article.getTitle(serviceContext.getLanguageId()), "[$ARTICLE_URL$]",
3222                            articleURL, "[$ARTICLE_VERSION$]", article.getVersion());
3223                    subscriptionSender.setContextUserPrefix("ARTICLE");
3224                    subscriptionSender.setFrom(fromAddress, fromName);
3225                    subscriptionSender.setHtmlFormat(true);
3226                    subscriptionSender.setMailId("journal_article", article.getId());
3227                    subscriptionSender.setPortletId(PortletKeys.JOURNAL);
3228                    subscriptionSender.setReplyToAddress(fromAddress);
3229                    subscriptionSender.setScopeGroupId(article.getGroupId());
3230                    subscriptionSender.setServiceContext(serviceContext);
3231                    subscriptionSender.setSubject(subject);
3232                    subscriptionSender.setUserId(article.getUserId());
3233    
3234                    subscriptionSender.addPersistedSubscribers(
3235                            JournalArticle.class.getName(), article.getGroupId());
3236    
3237                    subscriptionSender.flushNotificationsAsync();
3238            }
3239    
3240            protected void saveImages(
3241                            boolean smallImage, long smallImageId, File smallImageFile,
3242                            byte[] smallImageBytes)
3243                    throws PortalException, SystemException {
3244    
3245                    if (smallImage) {
3246                            if ((smallImageFile != null) && (smallImageBytes != null)) {
3247                                    imageLocalService.updateImage(smallImageId, smallImageBytes);
3248                            }
3249                    }
3250                    else {
3251                            imageLocalService.deleteImage(smallImageId);
3252                    }
3253            }
3254    
3255            protected void sendEmail(
3256                            JournalArticle article, String articleURL,
3257                            PortletPreferences preferences, String emailType,
3258                            ServiceContext serviceContext)
3259                    throws PortalException, SystemException {
3260    
3261                    if (preferences == null) {
3262                            return;
3263                    }
3264                    else if (emailType.equals("denied") &&
3265                                     JournalUtil.getEmailArticleApprovalDeniedEnabled(
3266                                             preferences)) {
3267                    }
3268                    else if (emailType.equals("granted") &&
3269                                     JournalUtil.getEmailArticleApprovalGrantedEnabled(
3270                                             preferences)) {
3271                    }
3272                    else if (emailType.equals("requested") &&
3273                                     JournalUtil.getEmailArticleApprovalRequestedEnabled(
3274                                             preferences)) {
3275                    }
3276                    else if (emailType.equals("review") &&
3277                                     JournalUtil.getEmailArticleReviewEnabled(preferences)) {
3278                    }
3279                    else {
3280                            return;
3281                    }
3282    
3283                    Company company = companyPersistence.findByPrimaryKey(
3284                            article.getCompanyId());
3285    
3286                    User user = userPersistence.findByPrimaryKey(article.getUserId());
3287    
3288                    articleURL +=
3289                            "&groupId=" + article.getGroupId() + "&articleId=" +
3290                                    article.getArticleId() + "&version=" + article.getVersion();
3291    
3292                    String fromName = JournalUtil.getEmailFromName(
3293                            preferences, article.getCompanyId());
3294                    String fromAddress = JournalUtil.getEmailFromAddress(
3295                            preferences, article.getCompanyId());
3296    
3297                    String toName = user.getFullName();
3298                    String toAddress = user.getEmailAddress();
3299    
3300                    if (emailType.equals("requested") || emailType.equals("review")) {
3301                            String tempToName = fromName;
3302                            String tempToAddress = fromAddress;
3303    
3304                            fromName = toName;
3305                            fromAddress = toAddress;
3306    
3307                            toName = tempToName;
3308                            toAddress = tempToAddress;
3309                    }
3310    
3311                    String subject = null;
3312                    String body = null;
3313    
3314                    if (emailType.equals("denied")) {
3315                            subject = JournalUtil.getEmailArticleApprovalDeniedSubject(
3316                                    preferences);
3317                            body = JournalUtil.getEmailArticleApprovalDeniedBody(preferences);
3318                    }
3319                    else if (emailType.equals("granted")) {
3320                            subject = JournalUtil.getEmailArticleApprovalGrantedSubject(
3321                                    preferences);
3322                            body = JournalUtil.getEmailArticleApprovalGrantedBody(preferences);
3323                    }
3324                    else if (emailType.equals("requested")) {
3325                            subject = JournalUtil.getEmailArticleApprovalRequestedSubject(
3326                                    preferences);
3327                            body = JournalUtil.getEmailArticleApprovalRequestedBody(
3328                                    preferences);
3329                    }
3330                    else if (emailType.equals("review")) {
3331                            subject = JournalUtil.getEmailArticleReviewSubject(preferences);
3332                            body = JournalUtil.getEmailArticleReviewBody(preferences);
3333                    }
3334    
3335                    SubscriptionSender subscriptionSender = new SubscriptionSender();
3336    
3337                    subscriptionSender.setBody(body);
3338                    subscriptionSender.setCompanyId(company.getCompanyId());
3339                    subscriptionSender.setContextAttributes(
3340                            "[$ARTICLE_ID$]", article.getArticleId(), "[$ARTICLE_TITLE$]",
3341                            article.getTitle(serviceContext.getLanguageId()), "[$ARTICLE_URL$]",
3342                            articleURL, "[$ARTICLE_USER_NAME$]", article.getUserName(),
3343                            "[$ARTICLE_VERSION$]", article.getVersion());
3344                    subscriptionSender.setContextUserPrefix("ARTICLE");
3345                    subscriptionSender.setFrom(fromAddress, fromName);
3346                    subscriptionSender.setHtmlFormat(true);
3347                    subscriptionSender.setMailId("journal_article", article.getId());
3348                    subscriptionSender.setPortletId(PortletKeys.JOURNAL);
3349                    subscriptionSender.setScopeGroupId(article.getGroupId());
3350                    subscriptionSender.setServiceContext(serviceContext);
3351                    subscriptionSender.setSubject(subject);
3352                    subscriptionSender.setUserId(article.getUserId());
3353    
3354                    subscriptionSender.addRuntimeSubscribers(toAddress, toName);
3355    
3356                    subscriptionSender.flushNotificationsAsync();
3357            }
3358    
3359            protected void updatePreviousApprovedArticle(JournalArticle article)
3360                    throws PortalException, SystemException {
3361    
3362                    List<JournalArticle> approvedArticles =
3363                            journalArticlePersistence.findByG_A_ST(
3364                                    article.getGroupId(), article.getArticleId(),
3365                                    WorkflowConstants.STATUS_APPROVED, 0, 2);
3366    
3367                    if (approvedArticles.isEmpty() ||
3368                            ((approvedArticles.size() == 1) &&
3369                             (article.getStatus() == WorkflowConstants.STATUS_APPROVED))) {
3370    
3371                            if (article.isIndexable()) {
3372                                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
3373                                            JournalArticle.class);
3374    
3375                                    indexer.delete(article);
3376                            }
3377    
3378                            assetEntryLocalService.updateVisible(
3379                                    JournalArticle.class.getName(), article.getResourcePrimKey(),
3380                                    false);
3381                    }
3382                    else {
3383                            JournalArticle previousApprovedArticle = approvedArticles.get(0);
3384    
3385                            if (article.getStatus() == WorkflowConstants.STATUS_APPROVED) {
3386                                    previousApprovedArticle = approvedArticles.get(1);
3387                            }
3388    
3389                            Date[] dateInterval = getDateInterval(
3390                                    previousApprovedArticle.getGroupId(),
3391                                    previousApprovedArticle.getArticleId(),
3392                                    previousApprovedArticle.getDisplayDate(),
3393                                    previousApprovedArticle.getExpirationDate());
3394    
3395                            Date displayDate = dateInterval[0];
3396                            Date expirationDate = dateInterval[1];
3397    
3398                            AssetEntry assetEntry = assetEntryLocalService.updateEntry(
3399                                    JournalArticle.class.getName(), article.getResourcePrimKey(),
3400                                    displayDate, expirationDate, true);
3401    
3402                            assetEntry.setModifiedDate(
3403                                    previousApprovedArticle.getModifiedDate());
3404    
3405                            assetEntryPersistence.update(assetEntry, false);
3406    
3407                            if (article.isIndexable()) {
3408                                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
3409                                            JournalArticle.class);
3410    
3411                                    indexer.reindex(previousApprovedArticle);
3412                            }
3413                    }
3414            }
3415    
3416            protected void updateUrlTitles(
3417                            long groupId, String articleId, String urlTitle)
3418                    throws SystemException {
3419    
3420                    List<JournalArticle> articles = journalArticlePersistence.findByG_A(
3421                            groupId, articleId);
3422    
3423                    for (JournalArticle article : articles) {
3424                            if (!article.getUrlTitle().equals(urlTitle)) {
3425                                    article.setUrlTitle(urlTitle);
3426    
3427                                    journalArticlePersistence.update(article, false);
3428                            }
3429                    }
3430            }
3431    
3432            protected void validate(
3433                            long companyId, long groupId, long classNameId,
3434                            Map<Locale, String> titleMap, String content, String type,
3435                            String structureId, String templateId, boolean smallImage,
3436                            String smallImageURL, File smallImageFile, byte[] smallImageBytes)
3437                    throws PortalException, SystemException {
3438    
3439                    Locale articleDefaultLocale = LocaleUtil.fromLanguageId(
3440                            LocalizationUtil.getDefaultLocale(content));
3441    
3442                    Locale[] availableLocales = LanguageUtil.getAvailableLocales();
3443    
3444                    if (!ArrayUtil.contains(availableLocales, articleDefaultLocale)) {
3445                            LocaleException le = new LocaleException();
3446    
3447                            Locale[] sourceAvailableLocales = {articleDefaultLocale};
3448    
3449                            le.setSourceAvailableLocales(sourceAvailableLocales);
3450                            le.setTargetAvailableLocales(availableLocales);
3451    
3452                            throw le;
3453                    }
3454    
3455                    if ((classNameId == 0) &&
3456                            (titleMap.isEmpty() ||
3457                             Validator.isNull(titleMap.get(articleDefaultLocale)))) {
3458    
3459                            throw new ArticleTitleException();
3460                    }
3461                    else if (Validator.isNull(type)) {
3462                            throw new ArticleTypeException();
3463                    }
3464    
3465                    validateContent(content);
3466    
3467                    if (Validator.isNotNull(structureId)) {
3468                            Group companyGroup = groupLocalService.getCompanyGroup(companyId);
3469    
3470                            try {
3471                                    journalStructurePersistence.findByG_S(groupId, structureId);
3472                            }
3473                            catch (NoSuchStructureException nsse) {
3474                                    journalStructurePersistence.findByG_S(
3475                                            companyGroup.getGroupId(), structureId);
3476                            }
3477    
3478                            JournalTemplate template = null;
3479    
3480                            if (Validator.isNotNull(templateId)) {
3481                                    try {
3482                                            template = journalTemplatePersistence.findByG_T(
3483                                                    groupId, templateId);
3484                                    }
3485                                    catch (NoSuchTemplateException nste) {
3486                                            template = journalTemplatePersistence.findByG_T(
3487                                                    companyGroup.getGroupId(), templateId);
3488                                    }
3489    
3490                                    if (!template.getStructureId().equals(structureId)) {
3491                                            throw new NoSuchTemplateException();
3492                                    }
3493                            }
3494                            else if (classNameId == 0) {
3495                                    throw new NoSuchTemplateException();
3496                            }
3497                    }
3498    
3499                    String[] imageExtensions = PrefsPropsUtil.getStringArray(
3500                            PropsKeys.JOURNAL_IMAGE_EXTENSIONS, StringPool.COMMA);
3501    
3502                    if (smallImage && Validator.isNull(smallImageURL) &&
3503                            (smallImageFile != null) && (smallImageBytes != null)) {
3504    
3505                            String smallImageName = smallImageFile.getName();
3506    
3507                            if (smallImageName != null) {
3508                                    boolean validSmallImageExtension = false;
3509    
3510                                    for (String _imageExtension : imageExtensions) {
3511                                            if (StringPool.STAR.equals(_imageExtension) ||
3512                                                    StringUtil.endsWith(smallImageName, _imageExtension)) {
3513    
3514                                                    validSmallImageExtension = true;
3515    
3516                                                    break;
3517                                            }
3518                                    }
3519    
3520                                    if (!validSmallImageExtension) {
3521                                            throw new ArticleSmallImageNameException(smallImageName);
3522                                    }
3523                            }
3524    
3525                            long smallImageMaxSize = PrefsPropsUtil.getLong(
3526                                    PropsKeys.JOURNAL_IMAGE_SMALL_MAX_SIZE);
3527    
3528                            if ((smallImageMaxSize > 0) &&
3529                                    ((smallImageBytes == null) ||
3530                                     (smallImageBytes.length > smallImageMaxSize))) {
3531    
3532                                    throw new ArticleSmallImageSizeException();
3533                            }
3534                    }
3535            }
3536    
3537            protected void validate(
3538                            long companyId, long groupId, long classNameId, String articleId,
3539                            boolean autoArticleId, double version, Map<Locale, String> titleMap,
3540                            String content, String type, String structureId, String templateId,
3541                            boolean smallImage, String smallImageURL, File smallImageFile,
3542                            byte[] smallImageBytes)
3543                    throws PortalException, SystemException {
3544    
3545                    if (!autoArticleId) {
3546                            validate(groupId, articleId);
3547                    }
3548    
3549                    validate(
3550                            companyId, groupId, classNameId, titleMap, content, type,
3551                            structureId, templateId, smallImage, smallImageURL, smallImageFile,
3552                            smallImageBytes);
3553            }
3554    
3555            protected void validate(long groupId, String articleId)
3556                    throws PortalException, SystemException {
3557    
3558                    if (Validator.isNull(articleId) ||
3559                            (articleId.indexOf(CharPool.SPACE) != -1)) {
3560    
3561                            throw new ArticleIdException();
3562                    }
3563    
3564                    if (journalArticlePersistence.countByG_A(groupId, articleId) > 0) {
3565                            throw new DuplicateArticleIdException();
3566                    }
3567            }
3568    
3569            protected void validateContent(String content) throws PortalException {
3570                    if (Validator.isNull(content)) {
3571                            throw new ArticleContentException("Content is null");
3572                    }
3573    
3574                    try {
3575                            SAXReaderUtil.read(content);
3576                    }
3577                    catch (DocumentException de) {
3578                            if (_log.isDebugEnabled()) {
3579                                    _log.debug("Invalid content:\n" + content);
3580                            }
3581    
3582                            throw new ArticleContentException(
3583                                    "Unable to read content with an XML parser", de);
3584                    }
3585            }
3586    
3587            private static final long _JOURNAL_ARTICLE_CHECK_INTERVAL =
3588                    PropsValues.JOURNAL_ARTICLE_CHECK_INTERVAL * Time.MINUTE;
3589    
3590            private static Log _log = LogFactoryUtil.getLog(
3591                    JournalArticleLocalServiceImpl.class);
3592    
3593    }