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