001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portlet.journal.lar;
016    
017    import com.liferay.portal.NoSuchImageException;
018    import com.liferay.portal.kernel.dao.orm.QueryUtil;
019    import com.liferay.portal.kernel.exception.PortalException;
020    import com.liferay.portal.kernel.exception.SystemException;
021    import com.liferay.portal.kernel.lar.BasePortletDataHandler;
022    import com.liferay.portal.kernel.lar.ExportImportPathUtil;
023    import com.liferay.portal.kernel.lar.PortletDataContext;
024    import com.liferay.portal.kernel.lar.PortletDataHandlerBoolean;
025    import com.liferay.portal.kernel.lar.PortletDataHandlerControl;
026    import com.liferay.portal.kernel.lar.StagedModelDataHandlerUtil;
027    import com.liferay.portal.kernel.log.Log;
028    import com.liferay.portal.kernel.log.LogFactoryUtil;
029    import com.liferay.portal.kernel.repository.model.FileEntry;
030    import com.liferay.portal.kernel.util.ArrayUtil;
031    import com.liferay.portal.kernel.util.CalendarFactoryUtil;
032    import com.liferay.portal.kernel.util.CharPool;
033    import com.liferay.portal.kernel.util.FileUtil;
034    import com.liferay.portal.kernel.util.GetterUtil;
035    import com.liferay.portal.kernel.util.LocaleUtil;
036    import com.liferay.portal.kernel.util.LocalizationUtil;
037    import com.liferay.portal.kernel.util.MapUtil;
038    import com.liferay.portal.kernel.util.StringBundler;
039    import com.liferay.portal.kernel.util.StringPool;
040    import com.liferay.portal.kernel.util.StringUtil;
041    import com.liferay.portal.kernel.util.Validator;
042    import com.liferay.portal.kernel.workflow.WorkflowConstants;
043    import com.liferay.portal.kernel.xml.Element;
044    import com.liferay.portal.model.Group;
045    import com.liferay.portal.model.Image;
046    import com.liferay.portal.model.Layout;
047    import com.liferay.portal.model.Repository;
048    import com.liferay.portal.model.RepositoryEntry;
049    import com.liferay.portal.model.User;
050    import com.liferay.portal.service.GroupLocalServiceUtil;
051    import com.liferay.portal.service.ServiceContext;
052    import com.liferay.portal.service.UserLocalServiceUtil;
053    import com.liferay.portal.service.persistence.ImageUtil;
054    import com.liferay.portal.service.persistence.LayoutUtil;
055    import com.liferay.portal.util.PortalUtil;
056    import com.liferay.portal.util.PortletKeys;
057    import com.liferay.portal.util.PropsValues;
058    import com.liferay.portlet.documentlibrary.model.DLFileEntry;
059    import com.liferay.portlet.documentlibrary.model.DLFileRank;
060    import com.liferay.portlet.documentlibrary.model.DLFolder;
061    import com.liferay.portlet.documentlibrary.service.DLAppLocalServiceUtil;
062    import com.liferay.portlet.documentlibrary.util.DLUtil;
063    import com.liferay.portlet.dynamicdatamapping.lar.DDMPortletDataHandler;
064    import com.liferay.portlet.dynamicdatamapping.model.DDMStructure;
065    import com.liferay.portlet.dynamicdatamapping.model.DDMTemplate;
066    import com.liferay.portlet.dynamicdatamapping.service.DDMStructureLocalServiceUtil;
067    import com.liferay.portlet.dynamicdatamapping.service.DDMTemplateLocalServiceUtil;
068    import com.liferay.portlet.dynamicdatamapping.service.persistence.DDMStructureUtil;
069    import com.liferay.portlet.dynamicdatamapping.service.persistence.DDMTemplateUtil;
070    import com.liferay.portlet.dynamicdatamapping.util.comparator.StructureIdComparator;
071    import com.liferay.portlet.journal.ArticleContentException;
072    import com.liferay.portlet.journal.FeedTargetLayoutFriendlyUrlException;
073    import com.liferay.portlet.journal.NoSuchArticleException;
074    import com.liferay.portlet.journal.model.JournalArticle;
075    import com.liferay.portlet.journal.model.JournalArticleConstants;
076    import com.liferay.portlet.journal.model.JournalArticleImage;
077    import com.liferay.portlet.journal.model.JournalArticleResource;
078    import com.liferay.portlet.journal.model.JournalFeed;
079    import com.liferay.portlet.journal.model.JournalFolder;
080    import com.liferay.portlet.journal.model.JournalFolderConstants;
081    import com.liferay.portlet.journal.service.JournalArticleLocalServiceUtil;
082    import com.liferay.portlet.journal.service.JournalFeedLocalServiceUtil;
083    import com.liferay.portlet.journal.service.JournalFolderLocalServiceUtil;
084    import com.liferay.portlet.journal.service.persistence.JournalArticleImageUtil;
085    import com.liferay.portlet.journal.service.persistence.JournalArticleResourceUtil;
086    import com.liferay.portlet.journal.service.persistence.JournalArticleUtil;
087    import com.liferay.portlet.journal.service.persistence.JournalFeedUtil;
088    import com.liferay.portlet.journal.service.persistence.JournalFolderUtil;
089    import com.liferay.portlet.journal.util.comparator.ArticleIDComparator;
090    
091    import java.io.File;
092    
093    import java.util.ArrayList;
094    import java.util.Calendar;
095    import java.util.Date;
096    import java.util.HashMap;
097    import java.util.List;
098    import java.util.Locale;
099    import java.util.Map;
100    import java.util.regex.Matcher;
101    import java.util.regex.Pattern;
102    
103    import javax.portlet.PortletPreferences;
104    
105    /**
106     * <p>
107     * Provides the Journal portlet export and import functionality, which is to
108     * clone all articles, structures, and templates associated with the layout's
109     * group. Upon import, new instances of the corresponding articles, structures,
110     * and templates are created or updated according to the DATA_MIRROW strategy
111     * The author of the newly created objects are determined by the
112     * JournalCreationStrategy class defined in <i>portal.properties</i>. That
113     * strategy also allows the text of the journal article to be modified prior to
114     * import.
115     * </p>
116     *
117     * <p>
118     * This <code>PortletDataHandler</code> differs from
119     * <code>JournalContentPortletDataHandlerImpl</code> in that it exports all
120     * articles owned by the group whether or not they are actually displayed in a
121     * portlet in the layout set.
122     * </p>
123     *
124     * @author Raymond Augé
125     * @author Joel Kozikowski
126     * @author Brian Wing Shun Chan
127     * @author Bruno Farache
128     * @author Karthik Sudarshan
129     * @author Wesley Gong
130     * @author Hugo Huijser
131     * @see    com.liferay.portal.kernel.lar.PortletDataHandler
132     * @see    com.liferay.portlet.journal.lar.JournalContentPortletDataHandler
133     * @see    com.liferay.portlet.journal.lar.JournalCreationStrategy
134     */
135    public class JournalPortletDataHandler extends BasePortletDataHandler {
136    
137            public static final String NAMESPACE = "journal";
138    
139            public static void exportArticle(
140                            PortletDataContext portletDataContext, Element articlesElement,
141                            Element ddmStructuresElement, Element ddmTemplatesElement,
142                            Element dlFileEntryTypesElement, Element dlFoldersElement,
143                            Element dlFileEntriesElement, Element dlFileRanksElement,
144                            Element dlRepositoriesElement, Element dlRepositoryEntriesElement,
145                            JournalArticle article, boolean checkDateRange)
146                    throws Exception {
147    
148                    if (checkDateRange &&
149                            !portletDataContext.isWithinDateRange(article.getModifiedDate())) {
150    
151                            return;
152                    }
153    
154                    if ((article.getStatus() != WorkflowConstants.STATUS_APPROVED) &&
155                            (article.getStatus() != WorkflowConstants.STATUS_EXPIRED)) {
156    
157                            return;
158                    }
159    
160                    String path = getArticlePath(portletDataContext, article);
161    
162                    if (!portletDataContext.isPathNotProcessed(path)) {
163                            return;
164                    }
165    
166                    // Clone this article to make sure changes to its content are never
167                    // persisted
168    
169                    article = (JournalArticle)article.clone();
170    
171                    Element articleElement = (Element)articlesElement.selectSingleNode(
172                            "//article[@path='".concat(path).concat("']"));
173    
174                    if (articleElement == null) {
175                            articleElement = articlesElement.addElement("article");
176                    }
177    
178                    articleElement.addAttribute(
179                            "article-resource-uuid", article.getArticleResourceUuid());
180    
181                    if (Validator.isNotNull(article.getStructureId())) {
182                            DDMStructure ddmStructure =
183                                    DDMStructureLocalServiceUtil.getStructure(
184                                            article.getGroupId(),
185                                            PortalUtil.getClassNameId(JournalArticle.class),
186                                            article.getStructureId(), true);
187    
188                            articleElement.addAttribute(
189                                    "ddm-structure-uuid", ddmStructure.getUuid());
190    
191                            StagedModelDataHandlerUtil.exportStagedModel(
192                                    portletDataContext, ddmStructure);
193                    }
194    
195                    if (Validator.isNotNull(article.getTemplateId())) {
196                            DDMTemplate ddmTemplate = DDMTemplateLocalServiceUtil.getTemplate(
197                                    article.getGroupId(),
198                                    PortalUtil.getClassNameId(DDMStructure.class),
199                                    article.getTemplateId(), true);
200    
201                            articleElement.addAttribute(
202                                    "ddm-template-uuid", ddmTemplate.getUuid());
203    
204                            StagedModelDataHandlerUtil.exportStagedModel(
205                                    portletDataContext, ddmTemplate);
206                    }
207    
208                    if (article.isSmallImage()) {
209                            Image smallImage = ImageUtil.fetchByPrimaryKey(
210                                    article.getSmallImageId());
211    
212                            if (Validator.isNotNull(article.getSmallImageURL())) {
213                                    String smallImageURL =
214                                            DDMPortletDataHandler.exportReferencedContent(
215                                                    portletDataContext, dlFileEntryTypesElement,
216                                                    dlFoldersElement, dlFileEntriesElement,
217                                                    dlFileRanksElement, dlRepositoriesElement,
218                                                    dlRepositoryEntriesElement, articleElement,
219                                                    article.getSmallImageURL().concat(StringPool.SPACE));
220    
221                                    article.setSmallImageURL(smallImageURL);
222                            }
223                            else if (smallImage != null) {
224                                    String smallImagePath = getArticleSmallImagePath(
225                                            portletDataContext, article);
226    
227                                    articleElement.addAttribute("small-image-path", smallImagePath);
228    
229                                    article.setSmallImageType(smallImage.getType());
230    
231                                    portletDataContext.addZipEntry(
232                                            smallImagePath, smallImage.getTextObj());
233                            }
234                    }
235    
236                    if (portletDataContext.getBooleanParameter(NAMESPACE, "images")) {
237                            String imagePath = getArticleImagePath(portletDataContext, article);
238    
239                            articleElement.addAttribute("image-path", imagePath);
240    
241                            List<JournalArticleImage> articleImages =
242                                    JournalArticleImageUtil.findByG_A_V(
243                                            article.getGroupId(), article.getArticleId(),
244                                            article.getVersion());
245    
246                            for (JournalArticleImage articleImage : articleImages) {
247                                    Image image = null;
248    
249                                    try {
250                                            image = ImageUtil.findByPrimaryKey(
251                                                    articleImage.getArticleImageId());
252                                    }
253                                    catch (NoSuchImageException nsie) {
254                                            continue;
255                                    }
256    
257                                    if (image.getTextObj() == null) {
258                                            continue;
259                                    }
260    
261                                    String articleImagePath = getArticleImagePath(
262                                            portletDataContext, article, articleImage, image);
263    
264                                    if (!portletDataContext.isPathNotProcessed(articleImagePath)) {
265                                            continue;
266                                    }
267    
268                                    portletDataContext.addZipEntry(
269                                            articleImagePath, image.getTextObj());
270                            }
271                    }
272    
273                    article.setStatusByUserUuid(article.getStatusByUserUuid());
274    
275                    if (portletDataContext.getBooleanParameter(
276                                    NAMESPACE, "embedded-assets")) {
277    
278                            String content = DDMPortletDataHandler.exportReferencedContent(
279                                    portletDataContext, dlFileEntryTypesElement, dlFoldersElement,
280                                    dlFileEntriesElement, dlFileRanksElement, dlRepositoriesElement,
281                                    dlRepositoryEntriesElement, articleElement,
282                                    article.getContent());
283    
284                            article.setContent(content);
285                    }
286    
287                    portletDataContext.addClassedModel(
288                            articleElement, path, article, NAMESPACE);
289            }
290    
291            public static String getArticlePath(
292                            PortletDataContext portletDataContext, JournalArticle article)
293                    throws Exception {
294    
295                    StringBundler sb = new StringBundler(8);
296    
297                    sb.append(
298                            ExportImportPathUtil.getPortletPath(
299                                    portletDataContext, PortletKeys.JOURNAL));
300                    sb.append("/articles/");
301                    sb.append(article.getArticleResourceUuid());
302                    sb.append(StringPool.SLASH);
303                    sb.append(article.getVersion());
304                    sb.append(StringPool.SLASH);
305                    sb.append("article.xml");
306    
307                    return sb.toString();
308            }
309    
310            public static void importArticle(
311                            PortletDataContext portletDataContext, Element articleElement)
312                    throws Exception {
313    
314                    String path = articleElement.attributeValue("path");
315    
316                    if (!portletDataContext.isPathNotProcessed(path)) {
317                            return;
318                    }
319    
320                    JournalArticle article =
321                            (JournalArticle)portletDataContext.getZipEntryAsObject(
322                                    articleElement, path);
323    
324                    prepareLanguagesForImport(article);
325    
326                    long userId = portletDataContext.getUserId(article.getUserUuid());
327    
328                    JournalCreationStrategy creationStrategy =
329                            JournalCreationStrategyFactory.getInstance();
330    
331                    long authorId = creationStrategy.getAuthorUserId(
332                            portletDataContext, article);
333    
334                    if (authorId != JournalCreationStrategy.USE_DEFAULT_USER_ID_STRATEGY) {
335                            userId = authorId;
336                    }
337    
338                    User user = UserLocalServiceUtil.getUser(userId);
339    
340                    Map<Long, Long> folderIds =
341                            (Map<Long, Long>)portletDataContext.getNewPrimaryKeysMap(
342                                    JournalFolder.class);
343    
344                    long folderId = MapUtil.getLong(
345                            folderIds, article.getFolderId(), article.getFolderId());
346    
347                    if ((folderId != JournalFolderConstants.DEFAULT_PARENT_FOLDER_ID) &&
348                            (folderId == article.getFolderId())) {
349    
350                            String folderPath = getImportFolderPath(
351                                    portletDataContext, folderId);
352    
353                            JournalFolder folder =
354                                    (JournalFolder)portletDataContext.getZipEntryAsObject(
355                                            folderPath);
356    
357                            importFolder(portletDataContext, folderPath, folder);
358    
359                            folderId = MapUtil.getLong(
360                                    folderIds, article.getFolderId(), article.getFolderId());
361                    }
362    
363                    String articleId = article.getArticleId();
364                    boolean autoArticleId = false;
365    
366                    if (Validator.isNumber(articleId) ||
367                            (JournalArticleUtil.fetchByG_A_V(
368                                    portletDataContext.getScopeGroupId(), articleId,
369                                    JournalArticleConstants.VERSION_DEFAULT) != null)) {
370    
371                            autoArticleId = true;
372                    }
373    
374                    Map<String, String> articleIds =
375                            (Map<String, String>)portletDataContext.getNewPrimaryKeysMap(
376                                    JournalArticle.class + ".articleId");
377    
378                    String newArticleId = articleIds.get(articleId);
379    
380                    if (Validator.isNotNull(newArticleId)) {
381    
382                            // A sibling of a different version was already assigned a new
383                            // article id
384    
385                            articleId = newArticleId;
386                            autoArticleId = false;
387                    }
388    
389                    String content = article.getContent();
390    
391                    content = importReferencedContent(
392                            portletDataContext, articleElement, content);
393    
394                    article.setContent(content);
395    
396                    String newContent = creationStrategy.getTransformedContent(
397                            portletDataContext, article);
398    
399                    if (newContent != JournalCreationStrategy.ARTICLE_CONTENT_UNCHANGED) {
400                            article.setContent(newContent);
401                    }
402    
403                    Map<String, String> ddmStructureKeys =
404                            (Map<String, String>)portletDataContext.getNewPrimaryKeysMap(
405                                    DDMStructure.class);
406    
407                    String parentDDMStructureKey = MapUtil.getString(
408                            ddmStructureKeys, article.getStructureId(),
409                            article.getStructureId());
410    
411                    Map<String, String> ddmTemplateKeys =
412                            (Map<String, String>)portletDataContext.getNewPrimaryKeysMap(
413                                    DDMTemplate.class);
414    
415                    String parentDDMTemplateKey = MapUtil.getString(
416                            ddmTemplateKeys, article.getTemplateId(), article.getTemplateId());
417    
418                    Date displayDate = article.getDisplayDate();
419    
420                    int displayDateMonth = 0;
421                    int displayDateDay = 0;
422                    int displayDateYear = 0;
423                    int displayDateHour = 0;
424                    int displayDateMinute = 0;
425    
426                    if (displayDate != null) {
427                            Calendar displayCal = CalendarFactoryUtil.getCalendar(
428                                    user.getTimeZone());
429    
430                            displayCal.setTime(displayDate);
431    
432                            displayDateMonth = displayCal.get(Calendar.MONTH);
433                            displayDateDay = displayCal.get(Calendar.DATE);
434                            displayDateYear = displayCal.get(Calendar.YEAR);
435                            displayDateHour = displayCal.get(Calendar.HOUR);
436                            displayDateMinute = displayCal.get(Calendar.MINUTE);
437    
438                            if (displayCal.get(Calendar.AM_PM) == Calendar.PM) {
439                                    displayDateHour += 12;
440                            }
441                    }
442    
443                    Date expirationDate = article.getExpirationDate();
444    
445                    int expirationDateMonth = 0;
446                    int expirationDateDay = 0;
447                    int expirationDateYear = 0;
448                    int expirationDateHour = 0;
449                    int expirationDateMinute = 0;
450                    boolean neverExpire = true;
451    
452                    if (expirationDate != null) {
453                            Calendar expirationCal = CalendarFactoryUtil.getCalendar(
454                                    user.getTimeZone());
455    
456                            expirationCal.setTime(expirationDate);
457    
458                            expirationDateMonth = expirationCal.get(Calendar.MONTH);
459                            expirationDateDay = expirationCal.get(Calendar.DATE);
460                            expirationDateYear = expirationCal.get(Calendar.YEAR);
461                            expirationDateHour = expirationCal.get(Calendar.HOUR);
462                            expirationDateMinute = expirationCal.get(Calendar.MINUTE);
463                            neverExpire = false;
464    
465                            if (expirationCal.get(Calendar.AM_PM) == Calendar.PM) {
466                                    expirationDateHour += 12;
467                            }
468                    }
469    
470                    Date reviewDate = article.getReviewDate();
471    
472                    int reviewDateMonth = 0;
473                    int reviewDateDay = 0;
474                    int reviewDateYear = 0;
475                    int reviewDateHour = 0;
476                    int reviewDateMinute = 0;
477                    boolean neverReview = true;
478    
479                    if (reviewDate != null) {
480                            Calendar reviewCal = CalendarFactoryUtil.getCalendar(
481                                    user.getTimeZone());
482    
483                            reviewCal.setTime(reviewDate);
484    
485                            reviewDateMonth = reviewCal.get(Calendar.MONTH);
486                            reviewDateDay = reviewCal.get(Calendar.DATE);
487                            reviewDateYear = reviewCal.get(Calendar.YEAR);
488                            reviewDateHour = reviewCal.get(Calendar.HOUR);
489                            reviewDateMinute = reviewCal.get(Calendar.MINUTE);
490                            neverReview = false;
491    
492                            if (reviewCal.get(Calendar.AM_PM) == Calendar.PM) {
493                                    reviewDateHour += 12;
494                            }
495                    }
496    
497                    long ddmStructureId = 0;
498    
499                    if (Validator.isNotNull(article.getStructureId())) {
500                            String ddmStructureUuid = articleElement.attributeValue(
501                                    "ddm-structure-uuid");
502    
503                            DDMStructure existingDDMStructure = DDMStructureUtil.fetchByUUID_G(
504                                    ddmStructureUuid, portletDataContext.getScopeGroupId());
505    
506                            if (existingDDMStructure == null) {
507                                    Group companyGroup = GroupLocalServiceUtil.getCompanyGroup(
508                                            portletDataContext.getCompanyId());
509    
510                                    long companyGroupId = companyGroup.getGroupId();
511    
512                                    existingDDMStructure = DDMStructureUtil.fetchByUUID_G(
513                                            ddmStructureUuid, companyGroupId);
514                            }
515    
516                            if (existingDDMStructure == null) {
517                                    String newStructureId = ddmStructureKeys.get(
518                                            article.getStructureId());
519    
520                                    if (Validator.isNotNull(newStructureId)) {
521                                            existingDDMStructure = DDMStructureUtil.fetchByG_C_S(
522                                                    portletDataContext.getScopeGroupId(),
523                                                    PortalUtil.getClassNameId(JournalArticle.class),
524                                                    String.valueOf(newStructureId));
525                                    }
526    
527                                    if (existingDDMStructure == null) {
528                                            if (_log.isWarnEnabled()) {
529                                                    StringBundler sb = new StringBundler();
530    
531                                                    sb.append("Structure ");
532                                                    sb.append(article.getStructureId());
533                                                    sb.append(" is missing for article ");
534                                                    sb.append(article.getArticleId());
535                                                    sb.append(", skipping this article.");
536    
537                                                    _log.warn(sb.toString());
538                                            }
539    
540                                            return;
541                                    }
542                            }
543    
544                            ddmStructureId = existingDDMStructure.getStructureId();
545    
546                            parentDDMStructureKey = existingDDMStructure.getStructureKey();
547                    }
548    
549                    if (Validator.isNotNull(article.getTemplateId())) {
550                            String ddmTemplateUuid = articleElement.attributeValue(
551                                    "ddm-template-uuid");
552    
553                            DDMTemplate existingDDMTemplate = DDMTemplateUtil.fetchByUUID_G(
554                                    ddmTemplateUuid, portletDataContext.getScopeGroupId());
555    
556                            if (existingDDMTemplate == null) {
557                                    Group companyGroup = GroupLocalServiceUtil.getCompanyGroup(
558                                            portletDataContext.getCompanyId());
559    
560                                    long companyGroupId = companyGroup.getGroupId();
561    
562                                    existingDDMTemplate = DDMTemplateUtil.fetchByUUID_G(
563                                            ddmTemplateUuid, companyGroupId);
564                            }
565    
566                            if (existingDDMTemplate == null) {
567                                    String newTemplateId = ddmTemplateKeys.get(
568                                            article.getTemplateId());
569    
570                                    if (Validator.isNotNull(newTemplateId)) {
571                                            existingDDMTemplate = DDMTemplateUtil.fetchByG_C_T(
572                                                    portletDataContext.getScopeGroupId(),
573                                                    PortalUtil.getClassNameId(DDMStructure.class),
574                                                    newTemplateId);
575                                    }
576    
577                                    if (existingDDMTemplate == null) {
578                                            if (_log.isWarnEnabled()) {
579                                                    StringBundler sb = new StringBundler();
580    
581                                                    sb.append("Template ");
582                                                    sb.append(article.getTemplateId());
583                                                    sb.append(" is missing for article ");
584                                                    sb.append(article.getArticleId());
585                                                    sb.append(", skipping this article.");
586    
587                                                    _log.warn(sb.toString());
588                                            }
589    
590                                            return;
591                                    }
592                            }
593    
594                            parentDDMTemplateKey = existingDDMTemplate.getTemplateKey();
595                    }
596    
597                    File smallFile = null;
598    
599                    if (article.isSmallImage()) {
600                            String smallImagePath = articleElement.attributeValue(
601                                    "small-image-path");
602    
603                            if (Validator.isNotNull(article.getSmallImageURL())) {
604                                    String smallImageURL = importReferencedContent(
605                                            portletDataContext, articleElement,
606                                            article.getSmallImageURL());
607    
608                                    article.setSmallImageURL(smallImageURL);
609                            }
610                            else if (Validator.isNotNull(smallImagePath)) {
611                                    byte[] bytes = portletDataContext.getZipEntryAsByteArray(
612                                            smallImagePath);
613    
614                                    if (bytes != null) {
615                                            smallFile = FileUtil.createTempFile(
616                                                    article.getSmallImageType());
617    
618                                            FileUtil.write(smallFile, bytes);
619                                    }
620                            }
621                    }
622    
623                    Map<String, byte[]> images = new HashMap<String, byte[]>();
624    
625                    String imagePath = articleElement.attributeValue("image-path");
626    
627                    if (portletDataContext.getBooleanParameter(NAMESPACE, "images") &&
628                            Validator.isNotNull(imagePath)) {
629    
630                            List<String> imageFiles = portletDataContext.getZipFolderEntries(
631                                    imagePath);
632    
633                            for (String imageFile : imageFiles) {
634                                    String fileName = imageFile;
635    
636                                    if (fileName.contains(StringPool.SLASH)) {
637                                            fileName = fileName.substring(
638                                                    fileName.lastIndexOf(CharPool.SLASH) + 1);
639                                    }
640    
641                                    if (fileName.endsWith(".xml")) {
642                                            continue;
643                                    }
644    
645                                    int pos = fileName.lastIndexOf(CharPool.PERIOD);
646    
647                                    if (pos != -1) {
648                                            fileName = fileName.substring(0, pos);
649                                    }
650    
651                                    images.put(
652                                            fileName,
653                                            portletDataContext.getZipEntryAsByteArray(imageFile));
654                            }
655                    }
656    
657                    String articleURL = null;
658    
659                    boolean addGroupPermissions = creationStrategy.addGroupPermissions(
660                            portletDataContext, article);
661                    boolean addGuestPermissions = creationStrategy.addGuestPermissions(
662                            portletDataContext, article);
663    
664                    ServiceContext serviceContext = portletDataContext.createServiceContext(
665                            articleElement, article, NAMESPACE);
666    
667                    serviceContext.setAddGroupPermissions(addGroupPermissions);
668                    serviceContext.setAddGuestPermissions(addGuestPermissions);
669    
670                    if (article.getStatus() != WorkflowConstants.STATUS_APPROVED) {
671                            serviceContext.setWorkflowAction(
672                                    WorkflowConstants.ACTION_SAVE_DRAFT);
673                    }
674    
675                    JournalArticle importedArticle = null;
676    
677                    String articleResourceUuid = articleElement.attributeValue(
678                            "article-resource-uuid");
679    
680                    if (portletDataContext.isDataStrategyMirror()) {
681                            JournalArticleResource articleResource =
682                                    JournalArticleResourceUtil.fetchByUUID_G(
683                                            articleResourceUuid, portletDataContext.getScopeGroupId());
684    
685                            if (articleResource == null) {
686                                    Group companyGroup = GroupLocalServiceUtil.getCompanyGroup(
687                                            portletDataContext.getCompanyId());
688    
689                                    long companyGroupId = companyGroup.getGroupId();
690    
691                                    articleResource = JournalArticleResourceUtil.fetchByUUID_G(
692                                            articleResourceUuid, companyGroupId);
693                            }
694    
695                            serviceContext.setUuid(articleResourceUuid);
696                            serviceContext.setAttribute("urlTitle", article.getUrlTitle());
697    
698                            JournalArticle existingArticle = null;
699    
700                            if (articleResource != null) {
701                                    try {
702                                            existingArticle =
703                                                    JournalArticleLocalServiceUtil.getLatestArticle(
704                                                            articleResource.getResourcePrimKey(),
705                                                            WorkflowConstants.STATUS_ANY, false);
706                                    }
707                                    catch (NoSuchArticleException nsae) {
708                                    }
709                            }
710    
711                            if (existingArticle == null) {
712                                    existingArticle = JournalArticleUtil.fetchByG_A_V(
713                                            portletDataContext.getScopeGroupId(), newArticleId,
714                                            article.getVersion());
715                            }
716    
717                            if (existingArticle == null) {
718                                    importedArticle = JournalArticleLocalServiceUtil.addArticle(
719                                            userId, portletDataContext.getScopeGroupId(), folderId,
720                                            article.getClassNameId(), ddmStructureId, articleId,
721                                            autoArticleId, article.getVersion(), article.getTitleMap(),
722                                            article.getDescriptionMap(), article.getContent(),
723                                            article.getType(), parentDDMStructureKey,
724                                            parentDDMTemplateKey, article.getLayoutUuid(),
725                                            displayDateMonth, displayDateDay, displayDateYear,
726                                            displayDateHour, displayDateMinute, expirationDateMonth,
727                                            expirationDateDay, expirationDateYear, expirationDateHour,
728                                            expirationDateMinute, neverExpire, reviewDateMonth,
729                                            reviewDateDay, reviewDateYear, reviewDateHour,
730                                            reviewDateMinute, neverReview, article.isIndexable(),
731                                            article.isSmallImage(), article.getSmallImageURL(),
732                                            smallFile, images, articleURL, serviceContext);
733                            }
734                            else {
735                                    importedArticle = JournalArticleLocalServiceUtil.updateArticle(
736                                            userId, existingArticle.getGroupId(), folderId,
737                                            existingArticle.getArticleId(), article.getVersion(),
738                                            article.getTitleMap(), article.getDescriptionMap(),
739                                            article.getContent(), article.getType(),
740                                            parentDDMStructureKey, parentDDMTemplateKey,
741                                            article.getLayoutUuid(), displayDateMonth, displayDateDay,
742                                            displayDateYear, displayDateHour, displayDateMinute,
743                                            expirationDateMonth, expirationDateDay, expirationDateYear,
744                                            expirationDateHour, expirationDateMinute, neverExpire,
745                                            reviewDateMonth, reviewDateDay, reviewDateYear,
746                                            reviewDateHour, reviewDateMinute, neverReview,
747                                            article.isIndexable(), article.isSmallImage(),
748                                            article.getSmallImageURL(), smallFile, images, articleURL,
749                                            serviceContext);
750                            }
751                    }
752                    else {
753                            importedArticle = JournalArticleLocalServiceUtil.addArticle(
754                                    userId, portletDataContext.getScopeGroupId(), folderId,
755                                    article.getClassNameId(), ddmStructureId, articleId,
756                                    autoArticleId, article.getVersion(), article.getTitleMap(),
757                                    article.getDescriptionMap(), article.getContent(),
758                                    article.getType(), parentDDMStructureKey, parentDDMTemplateKey,
759                                    article.getLayoutUuid(), displayDateMonth, displayDateDay,
760                                    displayDateYear, displayDateHour, displayDateMinute,
761                                    expirationDateMonth, expirationDateDay, expirationDateYear,
762                                    expirationDateHour, expirationDateMinute, neverExpire,
763                                    reviewDateMonth, reviewDateDay, reviewDateYear, reviewDateHour,
764                                    reviewDateMinute, neverReview, article.isIndexable(),
765                                    article.isSmallImage(), article.getSmallImageURL(), smallFile,
766                                    images, articleURL, serviceContext);
767                    }
768    
769                    if (smallFile != null) {
770                            smallFile.delete();
771                    }
772    
773                    portletDataContext.importClassedModel(
774                            article, importedArticle, NAMESPACE);
775    
776                    if (Validator.isNull(newArticleId)) {
777                            articleIds.put(
778                                    article.getArticleId(), importedArticle.getArticleId());
779                    }
780    
781                    if (!articleId.equals(importedArticle.getArticleId())) {
782                            if (_log.isWarnEnabled()) {
783                                    _log.warn(
784                                            "An article with the ID " + articleId + " already " +
785                                                    "exists. The new generated ID is " +
786                                                            importedArticle.getArticleId());
787                            }
788                    }
789            }
790    
791            public static void importFeed(
792                            PortletDataContext portletDataContext, Element feedElement)
793                    throws Exception {
794    
795                    String path = feedElement.attributeValue("path");
796    
797                    if (!portletDataContext.isPathNotProcessed(path)) {
798                            return;
799                    }
800    
801                    JournalFeed feed = (JournalFeed)portletDataContext.getZipEntryAsObject(
802                            path);
803    
804                    long userId = portletDataContext.getUserId(feed.getUserUuid());
805    
806                    JournalCreationStrategy creationStrategy =
807                            JournalCreationStrategyFactory.getInstance();
808    
809                    long authorId = creationStrategy.getAuthorUserId(
810                            portletDataContext, feed);
811    
812                    if (authorId != JournalCreationStrategy.USE_DEFAULT_USER_ID_STRATEGY) {
813                            userId = authorId;
814                    }
815    
816                    Group group = GroupLocalServiceUtil.getGroup(
817                            portletDataContext.getScopeGroupId());
818    
819                    String newGroupFriendlyURL = group.getFriendlyURL().substring(1);
820    
821                    String[] friendlyUrlParts = StringUtil.split(
822                            feed.getTargetLayoutFriendlyUrl(), '/');
823    
824                    String oldGroupFriendlyURL = friendlyUrlParts[2];
825    
826                    if (oldGroupFriendlyURL.equals("@data_handler_group_friendly_url@")) {
827                            feed.setTargetLayoutFriendlyUrl(
828                                    StringUtil.replace(
829                                            feed.getTargetLayoutFriendlyUrl(),
830                                            "@data_handler_group_friendly_url@", newGroupFriendlyURL));
831                    }
832    
833                    String feedId = feed.getFeedId();
834                    boolean autoFeedId = false;
835    
836                    if (Validator.isNumber(feedId) ||
837                            (JournalFeedUtil.fetchByG_F(
838                                    portletDataContext.getScopeGroupId(), feedId) != null)) {
839    
840                            autoFeedId = true;
841                    }
842    
843                    Map<String, String> ddmStructureKeys =
844                            (Map<String, String>)portletDataContext.getNewPrimaryKeysMap(
845                                    DDMStructure.class + ".structureKey");
846    
847                    String parentDDMStructureKey = MapUtil.getString(
848                            ddmStructureKeys, feed.getStructureId(), feed.getStructureId());
849    
850                    Map<String, String> ddmTemplateKeys =
851                            (Map<String, String>)portletDataContext.getNewPrimaryKeysMap(
852                                    DDMTemplate.class + ".templateKey");
853    
854                    String parentDDMTemplateKey = MapUtil.getString(
855                            ddmTemplateKeys, feed.getTemplateId(), feed.getTemplateId());
856                    String parentRenderDDMTemplateKey = MapUtil.getString(
857                            ddmTemplateKeys, feed.getRendererTemplateId(),
858                            feed.getRendererTemplateId());
859    
860                    boolean addGroupPermissions = creationStrategy.addGroupPermissions(
861                            portletDataContext, feed);
862                    boolean addGuestPermissions = creationStrategy.addGuestPermissions(
863                            portletDataContext, feed);
864    
865                    ServiceContext serviceContext = portletDataContext.createServiceContext(
866                            feedElement, feed, NAMESPACE);
867    
868                    serviceContext.setAddGroupPermissions(addGroupPermissions);
869                    serviceContext.setAddGuestPermissions(addGuestPermissions);
870    
871                    JournalFeed importedFeed = null;
872    
873                    try {
874                            if (portletDataContext.isDataStrategyMirror()) {
875                                    JournalFeed existingFeed = JournalFeedUtil.fetchByUUID_G(
876                                            feed.getUuid(), portletDataContext.getScopeGroupId());
877    
878                                    if (existingFeed == null) {
879                                            serviceContext.setUuid(feed.getUuid());
880    
881                                            importedFeed = JournalFeedLocalServiceUtil.addFeed(
882                                                    userId, portletDataContext.getScopeGroupId(), feedId,
883                                                    autoFeedId, feed.getName(), feed.getDescription(),
884                                                    feed.getType(), parentDDMStructureKey,
885                                                    parentDDMTemplateKey, parentRenderDDMTemplateKey,
886                                                    feed.getDelta(), feed.getOrderByCol(),
887                                                    feed.getOrderByType(),
888                                                    feed.getTargetLayoutFriendlyUrl(),
889                                                    feed.getTargetPortletId(), feed.getContentField(),
890                                                    feed.getFeedFormat(), feed.getFeedVersion(),
891                                                    serviceContext);
892                                    }
893                                    else {
894                                            importedFeed = JournalFeedLocalServiceUtil.updateFeed(
895                                                    existingFeed.getGroupId(), existingFeed.getFeedId(),
896                                                    feed.getName(), feed.getDescription(), feed.getType(),
897                                                    parentDDMStructureKey, parentDDMTemplateKey,
898                                                    parentRenderDDMTemplateKey, feed.getDelta(),
899                                                    feed.getOrderByCol(), feed.getOrderByType(),
900                                                    feed.getTargetLayoutFriendlyUrl(),
901                                                    feed.getTargetPortletId(), feed.getContentField(),
902                                                    feed.getFeedFormat(), feed.getFeedVersion(),
903                                                    serviceContext);
904                                    }
905                            }
906                            else {
907                                    importedFeed = JournalFeedLocalServiceUtil.addFeed(
908                                            userId, portletDataContext.getScopeGroupId(), feedId,
909                                            autoFeedId, feed.getName(), feed.getDescription(),
910                                            feed.getType(), parentDDMStructureKey, parentDDMTemplateKey,
911                                            parentRenderDDMTemplateKey, feed.getDelta(),
912                                            feed.getOrderByCol(), feed.getOrderByType(),
913                                            feed.getTargetLayoutFriendlyUrl(),
914                                            feed.getTargetPortletId(), feed.getContentField(),
915                                            feed.getFeedFormat(), feed.getFeedVersion(),
916                                            serviceContext);
917                            }
918    
919                            portletDataContext.importClassedModel(
920                                    feed, importedFeed, NAMESPACE);
921    
922                            if (!feedId.equals(importedFeed.getFeedId())) {
923                                    if (_log.isWarnEnabled()) {
924                                            StringBundler sb = new StringBundler(5);
925    
926                                            sb.append("A feed with the ID ");
927                                            sb.append(feedId);
928                                            sb.append(" already exists. The new generated ID is ");
929                                            sb.append(importedFeed.getFeedId());
930                                            sb.append(".");
931    
932                                            _log.warn(sb.toString());
933                                    }
934                            }
935                    }
936                    catch (FeedTargetLayoutFriendlyUrlException ftlfurle) {
937                            if (_log.isWarnEnabled()) {
938                                    StringBundler sb = new StringBundler(6);
939    
940                                    sb.append("A feed with the ID ");
941                                    sb.append(feedId);
942                                    sb.append(" cannot be imported because layout with friendly ");
943                                    sb.append("URL ");
944                                    sb.append(feed.getTargetLayoutFriendlyUrl());
945                                    sb.append(" does not exist");
946    
947                                    _log.warn(sb.toString());
948                            }
949                    }
950            }
951    
952            public static String importReferencedContent(
953                            PortletDataContext portletDataContext, Element parentElement,
954                            String content)
955                    throws Exception {
956    
957                    content = importDLFileEntries(
958                            portletDataContext, parentElement, content);
959                    content = importLayoutFriendlyURLs(portletDataContext, content);
960                    content = importLinksToLayout(portletDataContext, content);
961    
962                    return content;
963            }
964    
965            public static void importReferencedData(
966                            PortletDataContext portletDataContext, Element entityElement)
967                    throws Exception {
968    
969                    Element dlRepositoriesElement =
970                            portletDataContext.getImportDataGroupElement(Repository.class);
971    
972                    List<Element> dlRepositoryElements = dlRepositoriesElement.elements();
973    
974                    for (Element repositoryElement : dlRepositoryElements) {
975                            StagedModelDataHandlerUtil.importStagedModel(
976                                    portletDataContext, repositoryElement);
977                    }
978    
979                    Element dlRepositoryEntriesElement =
980                            portletDataContext.getImportDataGroupElement(RepositoryEntry.class);
981    
982                    List<Element> dlRepositoryEntryElements =
983                            dlRepositoryEntriesElement.elements();
984    
985                    for (Element dlRepositoryEntryElement : dlRepositoryEntryElements) {
986                            StagedModelDataHandlerUtil.importStagedModel(
987                                    portletDataContext, dlRepositoryEntryElement);
988                    }
989    
990                    Element dlFoldersElement = portletDataContext.getImportDataGroupElement(
991                            DLFolder.class);
992    
993                    List<Element> dlFolderElements = dlFoldersElement.elements();
994    
995                    for (Element folderElement : dlFolderElements) {
996                            StagedModelDataHandlerUtil.importStagedModel(
997                                    portletDataContext, folderElement);
998                    }
999    
1000                    Element dlFileEntriesElement =
1001                            portletDataContext.getImportDataGroupElement(DLFileEntry.class);
1002    
1003                    List<Element> dlFileEntryElements = dlFileEntriesElement.elements();
1004    
1005                    for (Element dlFileEntryElement : dlFileEntryElements) {
1006                            StagedModelDataHandlerUtil.importStagedModel(
1007                                    portletDataContext, dlFileEntryElement);
1008                    }
1009    
1010                    Element dlFileRanksElement =
1011                            portletDataContext.getImportDataGroupElement(DLFileRank.class);
1012    
1013                    List<Element> dlFileRankElements = dlFileRanksElement.elements();
1014    
1015                    for (Element dlFileRankElement : dlFileRankElements) {
1016                            StagedModelDataHandlerUtil.importStagedModel(
1017                                    portletDataContext, dlFileRankElement);
1018                    }
1019            }
1020    
1021            public JournalPortletDataHandler() {
1022                    setAlwaysExportable(true);
1023                    setDataLocalized(true);
1024                    setExportControls(
1025                            new PortletDataHandlerBoolean(NAMESPACE, "web-content"),
1026                            new PortletDataHandlerBoolean(
1027                                    NAMESPACE, "structures-templates-and-feeds", true, true),
1028                            new PortletDataHandlerBoolean(NAMESPACE, "embedded-assets"),
1029                            new PortletDataHandlerBoolean(
1030                                    NAMESPACE, "version-history",
1031                                    PropsValues.JOURNAL_PUBLISH_VERSION_HISTORY_BY_DEFAULT));
1032                    setExportMetadataControls(
1033                            new PortletDataHandlerBoolean(
1034                                    NAMESPACE, "web-content", true,
1035                                    new PortletDataHandlerControl[] {
1036                                            new PortletDataHandlerBoolean(NAMESPACE, "images"),
1037                                            new PortletDataHandlerBoolean(NAMESPACE, "categories"),
1038                                            new PortletDataHandlerBoolean(NAMESPACE, "comments"),
1039                                            new PortletDataHandlerBoolean(NAMESPACE, "ratings"),
1040                                            new PortletDataHandlerBoolean(NAMESPACE, "tags")
1041                                    }));
1042                    setImportControls(getExportControls()[0], getExportControls()[1]);
1043                    setPublishToLiveByDefault(
1044                            PropsValues.JOURNAL_PUBLISH_TO_LIVE_BY_DEFAULT);
1045            }
1046    
1047            protected static void exportFeed(
1048                            PortletDataContext portletDataContext, Element feedsElement,
1049                            JournalFeed feed)
1050                    throws Exception {
1051    
1052                    if (!portletDataContext.isWithinDateRange(feed.getModifiedDate())) {
1053                            return;
1054                    }
1055    
1056                    String path = getFeedPath(portletDataContext, feed);
1057    
1058                    if (!portletDataContext.isPathNotProcessed(path)) {
1059                            return;
1060                    }
1061    
1062                    feed = (JournalFeed)feed.clone();
1063    
1064                    Element feedElement = feedsElement.addElement("feed");
1065    
1066                    Group group = GroupLocalServiceUtil.getGroup(
1067                            portletDataContext.getScopeGroupId());
1068    
1069                    String newGroupFriendlyURL = group.getFriendlyURL().substring(1);
1070    
1071                    String[] friendlyUrlParts = StringUtil.split(
1072                            feed.getTargetLayoutFriendlyUrl(), '/');
1073    
1074                    String oldGroupFriendlyURL = friendlyUrlParts[2];
1075    
1076                    if (newGroupFriendlyURL.equals(oldGroupFriendlyURL)) {
1077                            String targetLayoutFriendlyUrl = StringUtil.replaceFirst(
1078                                    feed.getTargetLayoutFriendlyUrl(),
1079                                    StringPool.SLASH + newGroupFriendlyURL + StringPool.SLASH,
1080                                    "/@data_handler_group_friendly_url@/");
1081    
1082                            feed.setTargetLayoutFriendlyUrl(targetLayoutFriendlyUrl);
1083                    }
1084    
1085                    portletDataContext.addClassedModel(feedElement, path, feed, NAMESPACE);
1086            }
1087    
1088            protected static void exportFolder(
1089                            PortletDataContext portletDataContext, Element foldersElement,
1090                            Element articlesElement, Element ddmStructuresElement,
1091                            Element ddmTemplatesElement, Element dlFileEntryTypesElement,
1092                            Element dlFoldersElement, Element dlFileEntriesElement,
1093                            Element dlFileRanksElement, Element dlRepositoriesElement,
1094                            Element dlRepositoryEntriesElement, JournalFolder folder,
1095                            boolean checkDateRange)
1096                    throws Exception {
1097    
1098                    if (checkDateRange &&
1099                            !portletDataContext.isWithinDateRange(folder.getModifiedDate())) {
1100    
1101                            return;
1102                    }
1103    
1104                    exportParentFolder(
1105                            portletDataContext, foldersElement, folder.getParentFolderId());
1106    
1107                    String path = getFolderPath(portletDataContext, folder);
1108    
1109                    if (portletDataContext.isPathNotProcessed(path)) {
1110                            Element folderElement = foldersElement.addElement("folder");
1111    
1112                            portletDataContext.addClassedModel(
1113                                    folderElement, path, folder, NAMESPACE);
1114                    }
1115    
1116                    List<JournalArticle> articles = JournalArticleUtil.findByG_F(
1117                            folder.getGroupId(), folder.getFolderId());
1118    
1119                    for (JournalArticle article : articles) {
1120                            exportArticle(
1121                                    portletDataContext, articlesElement, ddmStructuresElement,
1122                                    ddmTemplatesElement, dlFileEntryTypesElement, dlFoldersElement,
1123                                    dlFileEntriesElement, dlFileRanksElement, dlRepositoriesElement,
1124                                    dlRepositoryEntriesElement, article, true);
1125                    }
1126            }
1127    
1128            protected static void exportParentFolder(
1129                            PortletDataContext portletDataContext, Element foldersElement,
1130                            long folderId)
1131                    throws Exception {
1132    
1133                    if (folderId == JournalFolderConstants.DEFAULT_PARENT_FOLDER_ID) {
1134                            return;
1135                    }
1136    
1137                    JournalFolder folder = JournalFolderUtil.findByPrimaryKey(folderId);
1138    
1139                    exportParentFolder(
1140                            portletDataContext, foldersElement, folder.getParentFolderId());
1141    
1142                    String path = getFolderPath(portletDataContext, folder);
1143    
1144                    if (portletDataContext.isPathNotProcessed(path)) {
1145                            Element folderElement = foldersElement.addElement("folder");
1146    
1147                            portletDataContext.addClassedModel(
1148                                    folderElement, path, folder, NAMESPACE);
1149                    }
1150            }
1151    
1152            protected static String getArticleImagePath(
1153                            PortletDataContext portletDataContext, JournalArticle article)
1154                    throws Exception {
1155    
1156                    StringBundler sb = new StringBundler(6);
1157    
1158                    sb.append(
1159                            ExportImportPathUtil.getPortletPath(
1160                                    portletDataContext, PortletKeys.JOURNAL));
1161                    sb.append("/articles/");
1162                    sb.append(article.getArticleResourceUuid());
1163                    sb.append(StringPool.SLASH);
1164                    sb.append(article.getVersion());
1165                    sb.append(StringPool.SLASH);
1166    
1167                    return sb.toString();
1168            }
1169    
1170            protected static String getArticleImagePath(
1171                            PortletDataContext portletDataContext, JournalArticle article,
1172                            JournalArticleImage articleImage, Image image)
1173                    throws Exception {
1174    
1175                    StringBundler sb = new StringBundler(12);
1176    
1177                    sb.append(
1178                            ExportImportPathUtil.getPortletPath(
1179                                    portletDataContext, PortletKeys.JOURNAL));
1180                    sb.append("/articles/");
1181                    sb.append(article.getArticleResourceUuid());
1182                    sb.append(StringPool.SLASH);
1183                    sb.append(article.getVersion());
1184                    sb.append(StringPool.SLASH);
1185                    sb.append(articleImage.getElInstanceId());
1186                    sb.append(StringPool.UNDERLINE);
1187                    sb.append(articleImage.getElName());
1188    
1189                    if (Validator.isNotNull(articleImage.getLanguageId())) {
1190                            sb.append(articleImage.getLanguageId());
1191                    }
1192    
1193                    sb.append(StringPool.PERIOD);
1194                    sb.append(image.getType());
1195    
1196                    return sb.toString();
1197            }
1198    
1199            protected static String getArticleSmallImagePath(
1200                            PortletDataContext portletDataContext, JournalArticle article)
1201                    throws Exception {
1202    
1203                    StringBundler sb = new StringBundler(6);
1204    
1205                    sb.append(
1206                            ExportImportPathUtil.getPortletPath(
1207                                    portletDataContext, PortletKeys.JOURNAL));
1208                    sb.append("/articles/");
1209                    sb.append(article.getArticleResourceUuid());
1210                    sb.append("/thumbnail");
1211                    sb.append(StringPool.PERIOD);
1212                    sb.append(article.getSmallImageType());
1213    
1214                    return sb.toString();
1215            }
1216    
1217            protected static String getDDMStructurePath(
1218                    PortletDataContext portletDataContext, String uuid) {
1219    
1220                    StringBundler sb = new StringBundler(4);
1221    
1222                    sb.append(
1223                            ExportImportPathUtil.getPortletPath(
1224                                    portletDataContext, PortletKeys.JOURNAL));
1225                    sb.append("/ddm-structures/");
1226                    sb.append(uuid);
1227                    sb.append(".xml");
1228    
1229                    return sb.toString();
1230            }
1231    
1232            protected static String getDDMTemplatePath(
1233                    PortletDataContext portletDataContext, DDMTemplate ddmTemplate) {
1234    
1235                    StringBundler sb = new StringBundler(4);
1236    
1237                    sb.append(
1238                            ExportImportPathUtil.getPortletPath(
1239                                    portletDataContext, PortletKeys.JOURNAL));
1240                    sb.append("/ddm-templates/");
1241                    sb.append(ddmTemplate.getUuid());
1242                    sb.append(".xml");
1243    
1244                    return sb.toString();
1245            }
1246    
1247            protected static String getFeedPath(
1248                    PortletDataContext portletDataContext, JournalFeed feed) {
1249    
1250                    StringBundler sb = new StringBundler(4);
1251    
1252                    sb.append(
1253                            ExportImportPathUtil.getPortletPath(
1254                                    portletDataContext, PortletKeys.JOURNAL));
1255                    sb.append("/feeds/");
1256                    sb.append(feed.getUuid());
1257                    sb.append(".xml");
1258    
1259                    return sb.toString();
1260            }
1261    
1262            protected static String getFolderPath(
1263                    PortletDataContext portletDataContext, JournalFolder folder) {
1264    
1265                    StringBundler sb = new StringBundler(4);
1266    
1267                    sb.append(
1268                            ExportImportPathUtil.getPortletPath(
1269                                    portletDataContext, PortletKeys.JOURNAL));
1270                    sb.append("/folders/");
1271                    sb.append(folder.getFolderId());
1272                    sb.append(".xml");
1273    
1274                    return sb.toString();
1275            }
1276    
1277            protected static String getImportFolderPath(
1278                    PortletDataContext portletDataContext, long folderId) {
1279    
1280                    StringBundler sb = new StringBundler(4);
1281    
1282                    sb.append(
1283                            ExportImportPathUtil.getPortletPath(
1284                                    portletDataContext, PortletKeys.JOURNAL));
1285                    sb.append("/folders/");
1286                    sb.append(folderId);
1287                    sb.append(".xml");
1288    
1289                    return sb.toString();
1290            }
1291    
1292            protected static String importDLFileEntries(
1293                            PortletDataContext portletDataContext, Element parentElement,
1294                            String content)
1295                    throws Exception {
1296    
1297                    List<Element> dlReferenceElements = parentElement.elements(
1298                            "dl-reference");
1299    
1300                    for (Element dlReferenceElement : dlReferenceElements) {
1301                            String dlReferencePath = dlReferenceElement.attributeValue("path");
1302    
1303                            String fileEntryUUID = null;
1304    
1305                            try {
1306                                    Object zipEntryObject = portletDataContext.getZipEntryAsObject(
1307                                            dlReferencePath);
1308    
1309                                    if (zipEntryObject == null) {
1310                                            if (_log.isWarnEnabled()) {
1311                                                    _log.warn("Unable to reference " + dlReferencePath);
1312                                            }
1313    
1314                                            continue;
1315                                    }
1316    
1317                                    boolean defaultRepository = GetterUtil.getBoolean(
1318                                            dlReferenceElement.attributeValue("default-repository"));
1319    
1320                                    if (defaultRepository) {
1321                                            FileEntry fileEntry = (FileEntry)zipEntryObject;
1322    
1323                                            fileEntryUUID = fileEntry.getUuid();
1324                                    }
1325                                    else {
1326                                            RepositoryEntry repositoryEntry =
1327                                                    (RepositoryEntry)zipEntryObject;
1328    
1329                                            fileEntryUUID = repositoryEntry.getUuid();
1330                                    }
1331                            }
1332                            catch (Exception e) {
1333                                    if (_log.isDebugEnabled()) {
1334                                            _log.debug(e, e);
1335                                    }
1336                                    else if (_log.isWarnEnabled()) {
1337                                            _log.warn(e.getMessage());
1338                                    }
1339                            }
1340    
1341                            if (fileEntryUUID == null) {
1342                                    continue;
1343                            }
1344    
1345                            FileEntry fileEntry =
1346                                    DLAppLocalServiceUtil.getFileEntryByUuidAndGroupId(
1347                                            fileEntryUUID, portletDataContext.getScopeGroupId());
1348    
1349                            if (fileEntry == null) {
1350                                    continue;
1351                            }
1352    
1353                            String dlReference = "[$dl-reference=" + dlReferencePath + "$]";
1354    
1355                            String url = DLUtil.getPreviewURL(
1356                                    fileEntry, fileEntry.getFileVersion(), null, StringPool.BLANK,
1357                                    false, false);
1358    
1359                            content = StringUtil.replace(content, dlReference, url);
1360                    }
1361    
1362                    return content;
1363            }
1364    
1365            protected static void importFolder(
1366                            PortletDataContext portletDataContext, Element folderElement)
1367                    throws Exception {
1368    
1369                    String path = folderElement.attributeValue("path");
1370    
1371                    if (!portletDataContext.isPathNotProcessed(path)) {
1372                            return;
1373                    }
1374    
1375                    JournalFolder folder =
1376                            (JournalFolder)portletDataContext.getZipEntryAsObject(path);
1377    
1378                    importFolder(portletDataContext, path, folder);
1379            }
1380    
1381            protected static void importFolder(
1382                            PortletDataContext portletDataContext, String folderPath,
1383                            JournalFolder folder)
1384                    throws Exception {
1385    
1386                    long userId = portletDataContext.getUserId(folder.getUserUuid());
1387    
1388                    Map<Long, Long> folderIds =
1389                            (Map<Long, Long>)portletDataContext.getNewPrimaryKeysMap(
1390                                    JournalFolder.class);
1391    
1392                    long parentFolderId = MapUtil.getLong(
1393                            folderIds, folder.getParentFolderId(), folder.getParentFolderId());
1394    
1395                    if ((parentFolderId !=
1396                                    JournalFolderConstants.DEFAULT_PARENT_FOLDER_ID) &&
1397                            (parentFolderId == folder.getParentFolderId())) {
1398    
1399                            String path = getImportFolderPath(
1400                                    portletDataContext, parentFolderId);
1401    
1402                            JournalFolder parentFolder =
1403                                    (JournalFolder)portletDataContext.getZipEntryAsObject(path);
1404    
1405                            importFolder(portletDataContext, path, parentFolder);
1406    
1407                            parentFolderId = MapUtil.getLong(
1408                                    folderIds, folder.getParentFolderId(),
1409                                    folder.getParentFolderId());
1410                    }
1411    
1412                    ServiceContext serviceContext = portletDataContext.createServiceContext(
1413                            folderPath, folder, NAMESPACE);
1414    
1415                    JournalFolder importedFolder = null;
1416    
1417                    long groupId = portletDataContext.getScopeGroupId();
1418    
1419                    if (portletDataContext.isDataStrategyMirror()) {
1420                            JournalFolder existingFolder = JournalFolderUtil.fetchByUUID_G(
1421                                    folder.getUuid(), groupId);
1422    
1423                            if (existingFolder == null) {
1424                                    serviceContext.setUuid(folder.getUuid());
1425    
1426                                    importedFolder = JournalFolderLocalServiceUtil.addFolder(
1427                                            userId, groupId, parentFolderId, folder.getName(),
1428                                            folder.getDescription(), serviceContext);
1429                            }
1430                            else {
1431                                    importedFolder = JournalFolderLocalServiceUtil.updateFolder(
1432                                            userId, existingFolder.getFolderId(), parentFolderId,
1433                                            folder.getName(), folder.getDescription(), false,
1434                                            serviceContext);
1435                            }
1436                    }
1437                    else {
1438                            importedFolder = JournalFolderLocalServiceUtil.addFolder(
1439                                    userId, groupId, parentFolderId, folder.getName(),
1440                                    folder.getDescription(), serviceContext);
1441                    }
1442    
1443                    portletDataContext.importClassedModel(
1444                            folder, importedFolder, NAMESPACE);
1445            }
1446    
1447            protected static String importLayoutFriendlyURLs(
1448                            PortletDataContext portletDataContext, String content)
1449                    throws Exception {
1450    
1451                    String privateGroupServletMapping =
1452                            PropsValues.LAYOUT_FRIENDLY_URL_PRIVATE_GROUP_SERVLET_MAPPING;
1453                    String privateUserServletMapping =
1454                            PropsValues.LAYOUT_FRIENDLY_URL_PRIVATE_USER_SERVLET_MAPPING;
1455                    String publicServletMapping =
1456                            PropsValues.LAYOUT_FRIENDLY_URL_PUBLIC_SERVLET_MAPPING;
1457    
1458                    String portalContextPath = PortalUtil.getPathContext();
1459    
1460                    if (Validator.isNotNull(portalContextPath)) {
1461                            privateGroupServletMapping = portalContextPath.concat(
1462                                    privateGroupServletMapping);
1463                            privateUserServletMapping = portalContextPath.concat(
1464                                    privateUserServletMapping);
1465                            publicServletMapping = portalContextPath.concat(
1466                                    publicServletMapping);
1467                    }
1468    
1469                    content = StringUtil.replace(
1470                            content, "@data_handler_private_group_servlet_mapping@",
1471                            privateGroupServletMapping);
1472                    content = StringUtil.replace(
1473                            content, "@data_handler_private_user_servlet_mapping@",
1474                            privateUserServletMapping);
1475                    content = StringUtil.replace(
1476                            content, "@data_handler_public_servlet_mapping@",
1477                            publicServletMapping);
1478    
1479                    Group group = GroupLocalServiceUtil.getGroup(
1480                            portletDataContext.getScopeGroupId());
1481    
1482                    content = StringUtil.replace(
1483                            content, "@data_handler_group_friendly_url@",
1484                            group.getFriendlyURL());
1485    
1486                    return content;
1487            }
1488    
1489            protected static String importLinksToLayout(
1490                            PortletDataContext portletDataContext, String content)
1491                    throws Exception {
1492    
1493                    List<String> oldLinksToLayout = new ArrayList<String>();
1494                    List<String> newLinksToLayout = new ArrayList<String>();
1495    
1496                    Matcher matcher = _importLinksToLayoutPattern.matcher(content);
1497    
1498                    while (matcher.find()) {
1499                            long oldLayoutId = GetterUtil.getLong(matcher.group(1));
1500    
1501                            long newLayoutId = oldLayoutId;
1502    
1503                            String type = matcher.group(2);
1504    
1505                            boolean privateLayout = type.startsWith("private");
1506    
1507                            String layoutUuid = matcher.group(3);
1508    
1509                            String friendlyURL = matcher.group(4);
1510    
1511                            try {
1512                                    Layout layout = LayoutUtil.fetchByUUID_G_P(
1513                                            layoutUuid, portletDataContext.getScopeGroupId(),
1514                                            privateLayout);
1515    
1516                                    if (layout == null) {
1517                                            layout = LayoutUtil.fetchByG_P_F(
1518                                                    portletDataContext.getScopeGroupId(), privateLayout,
1519                                                    friendlyURL);
1520                                    }
1521    
1522                                    if (layout == null) {
1523                                            layout = LayoutUtil.fetchByG_P_L(
1524                                                    portletDataContext.getScopeGroupId(), privateLayout,
1525                                                    oldLayoutId);
1526                                    }
1527    
1528                                    if (layout == null) {
1529                                            if (_log.isWarnEnabled()) {
1530                                                    StringBundler sb = new StringBundler(9);
1531    
1532                                                    sb.append("Unable to get layout with UUID ");
1533                                                    sb.append(layoutUuid);
1534                                                    sb.append(", friendly URL ");
1535                                                    sb.append(friendlyURL);
1536                                                    sb.append(", or ");
1537                                                    sb.append("layoutId ");
1538                                                    sb.append(oldLayoutId);
1539                                                    sb.append(" in group ");
1540                                                    sb.append(portletDataContext.getScopeGroupId());
1541    
1542                                                    _log.warn(sb.toString());
1543                                            }
1544                                    }
1545                                    else {
1546                                            newLayoutId = layout.getLayoutId();
1547                                    }
1548                            }
1549                            catch (SystemException se) {
1550                                    if (_log.isWarnEnabled()) {
1551                                            _log.warn(
1552                                                    "Unable to get layout in group " +
1553                                                            portletDataContext.getScopeGroupId(), se);
1554                                    }
1555                            }
1556    
1557                            String oldLinkToLayout = matcher.group(0);
1558    
1559                            StringBundler sb = new StringBundler(4);
1560    
1561                            sb.append(StringPool.AT);
1562                            sb.append(layoutUuid);
1563                            sb.append(StringPool.AT);
1564                            sb.append(friendlyURL);
1565    
1566                            String newLinkToLayout = StringUtil.replace(
1567                                    oldLinkToLayout,
1568                                    new String[] {sb.toString(), String.valueOf(oldLayoutId)},
1569                                    new String[] {StringPool.BLANK, String.valueOf(newLayoutId)});
1570    
1571                            oldLinksToLayout.add(oldLinkToLayout);
1572                            newLinksToLayout.add(newLinkToLayout);
1573                    }
1574    
1575                    content = StringUtil.replace(
1576                            content, ArrayUtil.toStringArray(oldLinksToLayout.toArray()),
1577                            ArrayUtil.toStringArray(newLinksToLayout.toArray()));
1578    
1579                    return content;
1580            }
1581    
1582            protected static void prepareLanguagesForImport(JournalArticle article)
1583                    throws PortalException {
1584    
1585                    Locale articleDefaultLocale = LocaleUtil.fromLanguageId(
1586                            article.getDefaultLocale());
1587    
1588                    Locale[] articleAvailableLocales = LocaleUtil.fromLanguageIds(
1589                            article.getAvailableLocales());
1590    
1591                    Locale defaultImportLocale = LocalizationUtil.getDefaultImportLocale(
1592                            JournalArticle.class.getName(), article.getPrimaryKey(),
1593                            articleDefaultLocale, articleAvailableLocales);
1594    
1595                    article.prepareLocalizedFieldsForImport(defaultImportLocale);
1596            }
1597    
1598            @Override
1599            protected PortletPreferences doDeleteData(
1600                            PortletDataContext portletDataContext, String portletId,
1601                            PortletPreferences portletPreferences)
1602                    throws Exception {
1603    
1604                    if (portletDataContext.addPrimaryKey(
1605                                    JournalPortletDataHandler.class, "deleteData")) {
1606    
1607                            return portletPreferences;
1608                    }
1609    
1610                    JournalArticleLocalServiceUtil.deleteArticles(
1611                            portletDataContext.getScopeGroupId());
1612    
1613                    DDMTemplateLocalServiceUtil.deleteTemplates(
1614                            portletDataContext.getScopeGroupId());
1615    
1616                    DDMStructureLocalServiceUtil.deleteStructures(
1617                            portletDataContext.getScopeGroupId());
1618    
1619                    return portletPreferences;
1620            }
1621    
1622            @Override
1623            protected String doExportData(
1624                            PortletDataContext portletDataContext, String portletId,
1625                            PortletPreferences portletPreferences)
1626                    throws Exception {
1627    
1628                    portletDataContext.addPermissions(
1629                            "com.liferay.portlet.journal",
1630                            portletDataContext.getScopeGroupId());
1631    
1632                    Element rootElement = addExportDataRootElement(portletDataContext);
1633    
1634                    rootElement.addAttribute(
1635                            "group-id", String.valueOf(portletDataContext.getScopeGroupId()));
1636    
1637                    Element ddmStructuresElement =
1638                            portletDataContext.getExportDataGroupElement(DDMStructure.class);
1639    
1640                    List<DDMStructure> ddmStructures = DDMStructureUtil.findByG_C(
1641                            portletDataContext.getScopeGroupId(),
1642                            PortalUtil.getClassNameId(JournalArticle.class), QueryUtil.ALL_POS,
1643                            QueryUtil.ALL_POS, new StructureIdComparator(true));
1644    
1645                    List<DDMTemplate> ddmTemplates = new ArrayList<DDMTemplate>();
1646    
1647                    for (DDMStructure ddmStructure : ddmStructures) {
1648                            if (portletDataContext.isWithinDateRange(
1649                                            ddmStructure.getModifiedDate())) {
1650    
1651                                    StagedModelDataHandlerUtil.exportStagedModel(
1652                                            portletDataContext, ddmStructure);
1653                            }
1654    
1655                            ddmTemplates.addAll(ddmStructure.getTemplates());
1656                    }
1657    
1658                    Element ddmTemplatesElement =
1659                            portletDataContext.getExportDataGroupElement(DDMTemplate.class);
1660    
1661                    // Does not have staged model data handler yet
1662    
1663                    Element dlFileEntryTypesElement = rootElement.addElement(
1664                            "dl-file-entry-types");
1665                    Element dlFoldersElement = rootElement.addElement("dl-folders");
1666                    Element dlFilesElement = rootElement.addElement("dl-file-entries");
1667                    Element dlFileRanksElement = rootElement.addElement("dl-file-ranks");
1668                    Element dlRepositoriesElement = rootElement.addElement(
1669                            "dl-repositories");
1670                    Element dlRepositoryEntriesElement = rootElement.addElement(
1671                            "dl-repository-entries");
1672    
1673                    for (DDMTemplate ddmTemplate : ddmTemplates) {
1674                            if (portletDataContext.isWithinDateRange(
1675                                            ddmTemplate.getModifiedDate())) {
1676    
1677                                    StagedModelDataHandlerUtil.exportStagedModel(
1678                                            portletDataContext, ddmTemplate);
1679                            }
1680                    }
1681    
1682                    Element feedsElement = rootElement.addElement("feeds");
1683    
1684                    List<JournalFeed> feeds = JournalFeedUtil.findByGroupId(
1685                            portletDataContext.getScopeGroupId());
1686    
1687                    for (JournalFeed feed : feeds) {
1688                            if (portletDataContext.isWithinDateRange(feed.getModifiedDate())) {
1689                                    exportFeed(portletDataContext, feedsElement, feed);
1690                            }
1691                    }
1692    
1693                    Element foldersElement = rootElement.addElement("folders");
1694                    Element articlesElement = rootElement.addElement("articles");
1695    
1696                    if (portletDataContext.getBooleanParameter(NAMESPACE, "web-content")) {
1697                            List<JournalFolder> folders = JournalFolderUtil.findByGroupId(
1698                                    portletDataContext.getScopeGroupId());
1699    
1700                            for (JournalFolder folder : folders) {
1701                                    exportFolder(
1702                                            portletDataContext, foldersElement, articlesElement,
1703                                            ddmStructuresElement, ddmTemplatesElement,
1704                                            dlFileEntryTypesElement, dlFoldersElement, dlFilesElement,
1705                                            dlFileRanksElement, dlRepositoriesElement,
1706                                            dlRepositoryEntriesElement, folder, true);
1707                            }
1708    
1709                            List<JournalArticle> articles = JournalArticleUtil.findByG_F(
1710                                    portletDataContext.getScopeGroupId(),
1711                                    JournalFolderConstants.DEFAULT_PARENT_FOLDER_ID,
1712                                    QueryUtil.ALL_POS, QueryUtil.ALL_POS,
1713                                    new ArticleIDComparator(true));
1714    
1715                            for (JournalArticle article : articles) {
1716                                    if (portletDataContext.getBooleanParameter(
1717                                                    NAMESPACE, "version-history") ||
1718                                            JournalArticleLocalServiceUtil.isLatestVersion(
1719                                                    article.getGroupId(), article.getArticleId(),
1720                                                    article.getVersion(),
1721                                                    WorkflowConstants.STATUS_APPROVED)) {
1722    
1723                                            exportArticle(
1724                                                    portletDataContext, articlesElement,
1725                                                    ddmStructuresElement, ddmTemplatesElement,
1726                                                    dlFileEntryTypesElement, dlFoldersElement,
1727                                                    dlFilesElement, dlFileRanksElement,
1728                                                    dlRepositoriesElement, dlRepositoryEntriesElement,
1729                                                    article, true);
1730                                    }
1731                            }
1732                    }
1733    
1734                    return getExportDataRootElementString(rootElement);
1735            }
1736    
1737            @Override
1738            protected PortletPreferences doImportData(
1739                            PortletDataContext portletDataContext, String portletId,
1740                            PortletPreferences portletPreferences, String data)
1741                    throws Exception {
1742    
1743                    portletDataContext.importPermissions(
1744                            "com.liferay.portlet.journal",
1745                            portletDataContext.getSourceGroupId(),
1746                            portletDataContext.getScopeGroupId());
1747    
1748                    Element rootElement = portletDataContext.getImportDataRootElement();
1749    
1750                    importReferencedData(portletDataContext, rootElement);
1751    
1752                    Element ddmStructuresElement =
1753                            portletDataContext.getImportDataGroupElement(DDMStructure.class);
1754    
1755                    List<Element> ddmStructureElements = ddmStructuresElement.elements();
1756    
1757                    for (Element ddmStructureElement : ddmStructureElements) {
1758                            StagedModelDataHandlerUtil.importStagedModel(
1759                                    portletDataContext, ddmStructureElement);
1760                    }
1761    
1762                    Element ddmTemplatesElement =
1763                            portletDataContext.getImportDataGroupElement(DDMTemplate.class);
1764    
1765                    List<Element> ddmTemplateElements = ddmTemplatesElement.elements();
1766    
1767                    for (Element ddmTemplateElement : ddmTemplateElements) {
1768                            StagedModelDataHandlerUtil.importStagedModel(
1769                                    portletDataContext, ddmTemplateElement);
1770                    }
1771    
1772                    Element feedsElement = rootElement.element("feeds");
1773    
1774                    List<Element> feedElements = feedsElement.elements("feed");
1775    
1776                    for (Element feedElement : feedElements) {
1777                            importFeed(portletDataContext, feedElement);
1778                    }
1779    
1780                    if (portletDataContext.getBooleanParameter(NAMESPACE, "web-content")) {
1781                            Element foldersElement = rootElement.element("folders");
1782    
1783                            List<Element> folderElements = foldersElement.elements("folder");
1784    
1785                            for (Element folderElement : folderElements) {
1786                                    importFolder(portletDataContext, folderElement);
1787                            }
1788    
1789                            Element articlesElement = rootElement.element("articles");
1790    
1791                            List<Element> articleElements = articlesElement.elements("article");
1792    
1793                            for (Element articleElement : articleElements) {
1794                                    try {
1795                                            importArticle(portletDataContext, articleElement);
1796                                    }
1797                                    catch (ArticleContentException ace) {
1798                                            if (_log.isWarnEnabled()) {
1799                                                    String path = articleElement.attributeValue("path");
1800    
1801                                                    _log.warn(
1802                                                            "Skipping article with path " + path +
1803                                                                    " because of invalid content");
1804                                            }
1805                                    }
1806                            }
1807                    }
1808    
1809                    return portletPreferences;
1810            }
1811    
1812            private static Log _log = LogFactoryUtil.getLog(
1813                    JournalPortletDataHandler.class);
1814    
1815            private static Pattern _importLinksToLayoutPattern = Pattern.compile(
1816                    "\\[([0-9]+)@(public|private\\-[a-z]*)@(\\p{XDigit}{8}\\-" +
1817                    "(?:\\p{XDigit}{4}\\-){3}\\p{XDigit}{12})@([^\\]]*)\\]");
1818    
1819    }