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