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