001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portlet.layoutsadmin.lar;
016    
017    import com.liferay.counter.service.CounterLocalServiceUtil;
018    import com.liferay.portal.NoSuchLayoutException;
019    import com.liferay.portal.kernel.exception.PortalException;
020    import com.liferay.portal.kernel.exception.SystemException;
021    import com.liferay.portal.kernel.json.JSONFactoryUtil;
022    import com.liferay.portal.kernel.json.JSONObject;
023    import com.liferay.portal.kernel.lar.BaseStagedModelDataHandler;
024    import com.liferay.portal.kernel.lar.ExportImportPathUtil;
025    import com.liferay.portal.kernel.lar.PortletDataContext;
026    import com.liferay.portal.kernel.lar.PortletDataHandlerKeys;
027    import com.liferay.portal.kernel.lar.StagedModelDataHandlerUtil;
028    import com.liferay.portal.kernel.log.Log;
029    import com.liferay.portal.kernel.log.LogFactoryUtil;
030    import com.liferay.portal.kernel.staging.LayoutStagingUtil;
031    import com.liferay.portal.kernel.staging.StagingUtil;
032    import com.liferay.portal.kernel.util.ArrayUtil;
033    import com.liferay.portal.kernel.util.CharPool;
034    import com.liferay.portal.kernel.util.Constants;
035    import com.liferay.portal.kernel.util.GetterUtil;
036    import com.liferay.portal.kernel.util.LocaleUtil;
037    import com.liferay.portal.kernel.util.MapUtil;
038    import com.liferay.portal.kernel.util.StringBundler;
039    import com.liferay.portal.kernel.util.StringPool;
040    import com.liferay.portal.kernel.util.StringUtil;
041    import com.liferay.portal.kernel.util.UnicodeProperties;
042    import com.liferay.portal.kernel.util.Validator;
043    import com.liferay.portal.kernel.workflow.WorkflowConstants;
044    import com.liferay.portal.kernel.xml.Element;
045    import com.liferay.portal.lar.LayoutExporter;
046    import com.liferay.portal.model.Group;
047    import com.liferay.portal.model.Image;
048    import com.liferay.portal.model.Layout;
049    import com.liferay.portal.model.LayoutBranch;
050    import com.liferay.portal.model.LayoutConstants;
051    import com.liferay.portal.model.LayoutFriendlyURL;
052    import com.liferay.portal.model.LayoutPrototype;
053    import com.liferay.portal.model.LayoutRevision;
054    import com.liferay.portal.model.LayoutSet;
055    import com.liferay.portal.model.LayoutStagingHandler;
056    import com.liferay.portal.model.LayoutTemplate;
057    import com.liferay.portal.model.LayoutTypePortlet;
058    import com.liferay.portal.model.LayoutTypePortletConstants;
059    import com.liferay.portal.service.ImageLocalServiceUtil;
060    import com.liferay.portal.service.LayoutFriendlyURLLocalServiceUtil;
061    import com.liferay.portal.service.LayoutLocalServiceUtil;
062    import com.liferay.portal.service.LayoutPrototypeLocalServiceUtil;
063    import com.liferay.portal.service.LayoutRevisionLocalServiceUtil;
064    import com.liferay.portal.service.LayoutSetLocalServiceUtil;
065    import com.liferay.portal.service.LayoutTemplateLocalServiceUtil;
066    import com.liferay.portal.service.PortletLocalServiceUtil;
067    import com.liferay.portal.service.ResourceLocalServiceUtil;
068    import com.liferay.portal.service.ServiceContext;
069    import com.liferay.portal.service.ServiceContextThreadLocal;
070    import com.liferay.portal.util.PropsValues;
071    import com.liferay.portlet.journal.NoSuchArticleException;
072    import com.liferay.portlet.journal.model.JournalArticle;
073    import com.liferay.portlet.journal.service.JournalArticleLocalServiceUtil;
074    import com.liferay.portlet.journal.service.JournalContentSearchLocalServiceUtil;
075    import com.liferay.portlet.sites.util.SitesUtil;
076    
077    import java.io.IOException;
078    
079    import java.util.List;
080    import java.util.Locale;
081    import java.util.Map;
082    
083    /**
084     * @author Mate Thurzo
085     */
086    public class LayoutStagedModelDataHandler
087            extends BaseStagedModelDataHandler<Layout> {
088    
089            public static final String[] CLASS_NAMES = {Layout.class.getName()};
090    
091            @Override
092            public void deleteStagedModel(
093                            String uuid, long groupId, String className, String extraData)
094                    throws PortalException, SystemException {
095    
096                    JSONObject extraDataJSONObject = JSONFactoryUtil.createJSONObject(
097                            extraData);
098    
099                    boolean privateLayout = extraDataJSONObject.getBoolean("privateLayout");
100    
101                    Layout layout = LayoutLocalServiceUtil.fetchLayoutByUuidAndGroupId(
102                            uuid, groupId, privateLayout);
103    
104                    if (layout != null) {
105                            LayoutLocalServiceUtil.deleteLayout(
106                                    layout, true, new ServiceContext());
107                    }
108            }
109    
110            @Override
111            public String[] getClassNames() {
112                    return CLASS_NAMES;
113            }
114    
115            @Override
116            public String getDisplayName(Layout layout) {
117                    return layout.getNameCurrentValue();
118            }
119    
120            protected String[] appendPortletIds(
121                    String[] portletIds, String[] newPortletIds, String portletsMergeMode) {
122    
123                    for (String portletId : newPortletIds) {
124                            if (ArrayUtil.contains(portletIds, portletId)) {
125                                    continue;
126                            }
127    
128                            if (portletsMergeMode.equals(
129                                            PortletDataHandlerKeys.PORTLETS_MERGE_MODE_ADD_TO_BOTTOM)) {
130    
131                                    portletIds = ArrayUtil.append(portletIds, portletId);
132                            }
133                            else {
134                                    portletIds = ArrayUtil.append(
135                                            new String[] {portletId}, portletIds);
136                            }
137                    }
138    
139                    return portletIds;
140            }
141    
142            @Override
143            protected void doExportStagedModel(
144                            PortletDataContext portletDataContext, Layout layout)
145                    throws Exception {
146    
147                    LayoutRevision layoutRevision = null;
148    
149                    boolean exportLAR = MapUtil.getBoolean(
150                            portletDataContext.getParameterMap(), "exportLAR");
151    
152                    if (!exportLAR && LayoutStagingUtil.isBranchingLayout(layout) &&
153                            !layout.isTypeURL()) {
154    
155                            long layoutSetBranchId = MapUtil.getLong(
156                                    portletDataContext.getParameterMap(), "layoutSetBranchId");
157    
158                            if (layoutSetBranchId <= 0) {
159                                    return;
160                            }
161    
162                            layoutRevision = LayoutRevisionLocalServiceUtil.fetchLayoutRevision(
163                                    layoutSetBranchId, true, layout.getPlid());
164    
165                            if (layoutRevision == null) {
166                                    return;
167                            }
168    
169                            LayoutStagingHandler layoutStagingHandler =
170                                    LayoutStagingUtil.getLayoutStagingHandler(layout);
171    
172                            layoutStagingHandler.setLayoutRevision(layoutRevision);
173                    }
174    
175                    Element layoutElement = portletDataContext.getExportDataElement(layout);
176    
177                    populateElementLayoutMetadata(layoutElement, layout, layoutRevision);
178    
179                    layoutElement.addAttribute("action", Constants.ADD);
180    
181                    portletDataContext.setPlid(layout.getPlid());
182    
183                    long parentLayoutId = layout.getParentLayoutId();
184    
185                    if (parentLayoutId != LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
186                            Layout parentLayout = LayoutLocalServiceUtil.fetchLayout(
187                                    layout.getGroupId(), layout.isPrivateLayout(), parentLayoutId);
188    
189                            if (parentLayout != null) {
190                                    StagedModelDataHandlerUtil.exportReferenceStagedModel(
191                                            portletDataContext, layout, parentLayout,
192                                            PortletDataContext.REFERENCE_TYPE_PARENT);
193    
194                                    layoutElement.addAttribute(
195                                            "parent-layout-uuid", parentLayout.getUuid());
196                            }
197                    }
198    
199                    List<LayoutFriendlyURL> layoutFriendlyURLs =
200                            LayoutFriendlyURLLocalServiceUtil.getLayoutFriendlyURLs(
201                                    layout.getPlid());
202    
203                    for (LayoutFriendlyURL layoutFriendlyURL : layoutFriendlyURLs) {
204                            StagedModelDataHandlerUtil.exportReferenceStagedModel(
205                                    portletDataContext, layout, layoutFriendlyURL,
206                                    PortletDataContext.REFERENCE_TYPE_DEPENDENCY);
207                    }
208    
209                    if (layout.isIconImage()) {
210                            exportLayoutIconImage(portletDataContext, layout, layoutElement);
211                    }
212    
213                    if (layout.isTypeArticle()) {
214                            exportJournalArticle(portletDataContext, layout);
215                    }
216                    else if (layout.isTypeLinkToLayout()) {
217                            exportLinkedLayout(portletDataContext, layout, layoutElement);
218                    }
219    
220                    fixExportTypeSettings(layout);
221    
222                    exportTheme(portletDataContext, layout);
223    
224                    portletDataContext.addClassedModel(
225                            layoutElement, ExportImportPathUtil.getModelPath(layout), layout);
226            }
227    
228            @Override
229            protected void doImportStagedModel(
230                            PortletDataContext portletDataContext, Layout layout)
231                    throws Exception {
232    
233                    long groupId = portletDataContext.getGroupId();
234                    long userId = portletDataContext.getUserId(layout.getUserUuid());
235    
236                    Element layoutElement =
237                            portletDataContext.getImportDataStagedModelElement(layout);
238    
239                    String layoutUuid = GetterUtil.getString(
240                            layoutElement.attributeValue("layout-uuid"));
241    
242                    long layoutId = GetterUtil.getInteger(
243                            layoutElement.attributeValue("layout-id"));
244    
245                    long oldLayoutId = layoutId;
246    
247                    boolean privateLayout = portletDataContext.isPrivateLayout();
248    
249                    Map<Long, Layout> newLayoutsMap =
250                            (Map<Long, Layout>)portletDataContext.getNewPrimaryKeysMap(
251                                    Layout.class + ".layout");
252    
253                    String action = layoutElement.attributeValue("action");
254    
255                    if (action.equals(Constants.DELETE)) {
256                            Layout deletingLayout =
257                                    LayoutLocalServiceUtil.fetchLayoutByUuidAndGroupId(
258                                            layoutUuid, groupId, privateLayout);
259    
260                            if (layout != null) {
261                                    newLayoutsMap.put(oldLayoutId, layout);
262    
263                                    ServiceContext serviceContext =
264                                            ServiceContextThreadLocal.getServiceContext();
265    
266                                    LayoutLocalServiceUtil.deleteLayout(
267                                            deletingLayout, false, serviceContext);
268                            }
269    
270                            return;
271                    }
272    
273                    Layout existingLayout = null;
274                    Layout importedLayout = null;
275    
276                    String friendlyURL = layout.getFriendlyURL();
277    
278                    String layoutsImportMode = MapUtil.getString(
279                            portletDataContext.getParameterMap(),
280                            PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE,
281                            PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE_MERGE_BY_LAYOUT_UUID);
282    
283                    if (layoutsImportMode.equals(
284                                    PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE_ADD_AS_NEW)) {
285    
286                            layoutId = LayoutLocalServiceUtil.getNextLayoutId(
287                                    groupId, privateLayout);
288                            friendlyURL = StringPool.SLASH + layoutId;
289                    }
290                    else if (layoutsImportMode.equals(
291                                            PortletDataHandlerKeys.
292                                                    LAYOUTS_IMPORT_MODE_MERGE_BY_LAYOUT_NAME)) {
293    
294                            Locale locale = LocaleUtil.getSiteDefault();
295    
296                            String localizedName = layout.getName(locale);
297    
298                            List<Layout> previousLayouts = LayoutLocalServiceUtil.getLayouts(
299                                    groupId, privateLayout);
300    
301                            for (Layout curLayout : previousLayouts) {
302                                    if (localizedName.equals(curLayout.getName(locale)) ||
303                                            friendlyURL.equals(curLayout.getFriendlyURL())) {
304    
305                                            existingLayout = curLayout;
306    
307                                            break;
308                                    }
309                            }
310    
311                            if (existingLayout == null) {
312                                    layoutId = LayoutLocalServiceUtil.getNextLayoutId(
313                                            groupId, privateLayout);
314                            }
315                    }
316                    else if (layoutsImportMode.equals(
317                                            PortletDataHandlerKeys.
318                                                    LAYOUTS_IMPORT_MODE_CREATED_FROM_PROTOTYPE)) {
319    
320                            existingLayout = LayoutLocalServiceUtil.fetchLayoutByUuidAndGroupId(
321                                    layout.getUuid(), groupId, privateLayout);
322    
323                            if (SitesUtil.isLayoutModifiedSinceLastMerge(existingLayout)) {
324                                    newLayoutsMap.put(oldLayoutId, existingLayout);
325    
326                                    return;
327                            }
328    
329                            LayoutFriendlyURL layoutFriendlyURL =
330                                    LayoutFriendlyURLLocalServiceUtil.fetchFirstLayoutFriendlyURL(
331                                            groupId, privateLayout, friendlyURL);
332    
333                            if ((layoutFriendlyURL != null) && (existingLayout == null)) {
334                                    Layout mergeFailFriendlyURLLayout =
335                                            LayoutLocalServiceUtil.getLayout(
336                                                    layoutFriendlyURL.getPlid());
337    
338                                    SitesUtil.addMergeFailFriendlyURLLayout(
339                                            mergeFailFriendlyURLLayout);
340    
341                                    return;
342                            }
343                    }
344                    else {
345    
346                            // The default behaviour of import mode is
347                            // PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE_MERGE_BY_LAYOUT_UUID
348    
349                            existingLayout = LayoutLocalServiceUtil.fetchLayoutByUuidAndGroupId(
350                                    layout.getUuid(), groupId, privateLayout);
351    
352                            if (existingLayout == null) {
353                                    existingLayout =
354                                            LayoutLocalServiceUtil.fetchLayoutByFriendlyURL(
355                                                    groupId, privateLayout, friendlyURL);
356                            }
357    
358                            if (existingLayout == null) {
359                                    layoutId = LayoutLocalServiceUtil.getNextLayoutId(
360                                            groupId, privateLayout);
361                            }
362                    }
363    
364                    if (_log.isDebugEnabled()) {
365                            StringBundler sb = new StringBundler(7);
366    
367                            sb.append("Layout with {groupId=");
368                            sb.append(groupId);
369                            sb.append(",privateLayout=");
370                            sb.append(privateLayout);
371                            sb.append(",layoutId=");
372                            sb.append(layoutId);
373    
374                            if (existingLayout == null) {
375                                    sb.append("} does not exist");
376    
377                                    _log.debug(sb.toString());
378                            }
379                            else {
380                                    sb.append("} exists");
381    
382                                    _log.debug(sb.toString());
383                            }
384                    }
385    
386                    if (existingLayout == null) {
387                            long plid = CounterLocalServiceUtil.increment();
388    
389                            importedLayout = LayoutLocalServiceUtil.createLayout(plid);
390    
391                            if (layoutsImportMode.equals(
392                                            PortletDataHandlerKeys.
393                                                    LAYOUTS_IMPORT_MODE_CREATED_FROM_PROTOTYPE)) {
394    
395                                    importedLayout.setSourcePrototypeLayoutUuid(layout.getUuid());
396    
397                                    layoutId = LayoutLocalServiceUtil.getNextLayoutId(
398                                            groupId, privateLayout);
399                            }
400                            else {
401                                    importedLayout.setCreateDate(layout.getCreateDate());
402                                    importedLayout.setModifiedDate(layout.getModifiedDate());
403                                    importedLayout.setLayoutPrototypeUuid(
404                                            layout.getLayoutPrototypeUuid());
405                                    importedLayout.setLayoutPrototypeLinkEnabled(
406                                            layout.isLayoutPrototypeLinkEnabled());
407                                    importedLayout.setSourcePrototypeLayoutUuid(
408                                            layout.getSourcePrototypeLayoutUuid());
409                            }
410    
411                            importedLayout.setUuid(layout.getUuid());
412                            importedLayout.setGroupId(groupId);
413                            importedLayout.setPrivateLayout(privateLayout);
414                            importedLayout.setLayoutId(layoutId);
415    
416                            initNewLayoutPermissions(
417                                    portletDataContext.getCompanyId(), groupId, userId, layout,
418                                    importedLayout, privateLayout);
419    
420                            LayoutSet layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
421                                    groupId, privateLayout);
422    
423                            importedLayout.setLayoutSet(layoutSet);
424                    }
425                    else {
426                            importedLayout = existingLayout;
427                    }
428    
429                    portletDataContext.setPlid(importedLayout.getPlid());
430                    portletDataContext.setOldPlid(layout.getPlid());
431    
432                    newLayoutsMap.put(oldLayoutId, importedLayout);
433    
434                    long parentLayoutId = layout.getParentLayoutId();
435    
436                    String parentLayoutUuid = GetterUtil.getString(
437                            layoutElement.attributeValue("parent-layout-uuid"));
438    
439                    Element parentLayoutElement =
440                            portletDataContext.getReferenceDataElement(
441                                    layout, Layout.class, layout.getGroupId(), parentLayoutUuid);
442    
443                    if ((parentLayoutId != LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) &&
444                            (parentLayoutElement != null)) {
445    
446                            String parentLayoutPath = parentLayoutElement.attributeValue(
447                                    "path");
448    
449                            Layout parentLayout =
450                                    (Layout)portletDataContext.getZipEntryAsObject(
451                                            parentLayoutPath);
452    
453                            StagedModelDataHandlerUtil.importReferenceStagedModel(
454                                    portletDataContext, parentLayout);
455    
456                            Layout importedParentLayout = newLayoutsMap.get(parentLayoutId);
457    
458                            parentLayoutId = importedParentLayout.getLayoutId();
459                    }
460    
461                    if (_log.isDebugEnabled()) {
462                            StringBundler sb = new StringBundler(4);
463    
464                            sb.append("Importing layout with layout id ");
465                            sb.append(layoutId);
466                            sb.append(" and parent layout id ");
467                            sb.append(parentLayoutId);
468    
469                            _log.debug(sb.toString());
470                    }
471    
472                    importedLayout.setCompanyId(portletDataContext.getCompanyId());
473                    importedLayout.setParentLayoutId(parentLayoutId);
474                    importedLayout.setName(layout.getName());
475                    importedLayout.setTitle(layout.getTitle());
476                    importedLayout.setDescription(layout.getDescription());
477                    importedLayout.setKeywords(layout.getKeywords());
478                    importedLayout.setRobots(layout.getRobots());
479                    importedLayout.setType(layout.getType());
480    
481                    String portletsMergeMode = MapUtil.getString(
482                            portletDataContext.getParameterMap(),
483                            PortletDataHandlerKeys.PORTLETS_MERGE_MODE,
484                            PortletDataHandlerKeys.PORTLETS_MERGE_MODE_REPLACE);
485    
486                    if (layout.isTypeArticle()) {
487                            importJournalArticle(portletDataContext, layout);
488    
489                            updateTypeSettings(importedLayout, layout);
490                    }
491                    else if (layout.isTypePortlet() &&
492                                     Validator.isNotNull(layout.getTypeSettings()) &&
493                                     !portletsMergeMode.equals(
494                                             PortletDataHandlerKeys.PORTLETS_MERGE_MODE_REPLACE)) {
495    
496                            mergePortlets(
497                                    importedLayout, layout.getTypeSettings(), portletsMergeMode);
498                    }
499                    else if (layout.isTypeLinkToLayout()) {
500                            importLinkedLayout(
501                                    portletDataContext, layout, importedLayout, layoutElement,
502                                    newLayoutsMap);
503                    }
504                    else {
505                            updateTypeSettings(importedLayout, layout);
506                    }
507    
508                    importedLayout.setHidden(layout.isHidden());
509                    importedLayout.setFriendlyURL(
510                            getUniqueFriendlyURL(
511                                    portletDataContext, importedLayout, friendlyURL));
512                    importedLayout.setIconImage(false);
513    
514                    if (layout.isIconImage()) {
515                            importLayoutIconImage(
516                                    portletDataContext, importedLayout, layoutElement);
517                    }
518                    else {
519                            ImageLocalServiceUtil.deleteImage(importedLayout.getIconImageId());
520                    }
521    
522                    importedLayout.setPriority(layout.getPriority());
523                    importedLayout.setLayoutPrototypeUuid(layout.getLayoutPrototypeUuid());
524                    importedLayout.setLayoutPrototypeLinkEnabled(
525                            layout.isLayoutPrototypeLinkEnabled());
526    
527                    StagingUtil.updateLastImportSettings(
528                            layoutElement, importedLayout, portletDataContext);
529    
530                    fixImportTypeSettings(importedLayout);
531    
532                    importTheme(portletDataContext, layout, importedLayout);
533    
534                    LayoutLocalServiceUtil.updateLayout(importedLayout);
535    
536                    LayoutSetLocalServiceUtil.updatePageCount(groupId, privateLayout);
537    
538                    List<Layout> newLayouts = portletDataContext.getNewLayouts();
539    
540                    newLayouts.add(importedLayout);
541    
542                    Map<Long, Long> layoutPlids =
543                            (Map<Long, Long>)portletDataContext.getNewPrimaryKeysMap(
544                                    Layout.class);
545    
546                    layoutPlids.put(layout.getPlid(), importedLayout.getPlid());
547    
548                    importLayoutFriendlyURLs(portletDataContext, layout);
549    
550                    portletDataContext.importClassedModel(layout, importedLayout);
551            }
552    
553            protected void exportJournalArticle(
554                            PortletDataContext portletDataContext, Layout layout)
555                    throws Exception {
556    
557                    UnicodeProperties typeSettingsProperties =
558                            layout.getTypeSettingsProperties();
559    
560                    String articleId = typeSettingsProperties.getProperty(
561                            "article-id", StringPool.BLANK);
562    
563                    long articleGroupId = layout.getGroupId();
564    
565                    if (Validator.isNull(articleId)) {
566                            if (_log.isWarnEnabled()) {
567                                    _log.warn(
568                                            "No article id found in typeSettings of layout " +
569                                                    layout.getPlid());
570                            }
571                    }
572    
573                    JournalArticle article = null;
574    
575                    try {
576                            article = JournalArticleLocalServiceUtil.getLatestArticle(
577                                    articleGroupId, articleId, WorkflowConstants.STATUS_APPROVED);
578                    }
579                    catch (NoSuchArticleException nsae) {
580                            if (_log.isWarnEnabled()) {
581                                    StringBundler sb = new StringBundler(4);
582    
583                                    sb.append("No approved article found with group id ");
584                                    sb.append(articleGroupId);
585                                    sb.append(" and layout id ");
586                                    sb.append(articleId);
587    
588                                    _log.warn(sb.toString());
589                            }
590                    }
591    
592                    if (article == null) {
593                            return;
594                    }
595    
596                    StagedModelDataHandlerUtil.exportReferenceStagedModel(
597                            portletDataContext, layout, article,
598                            PortletDataContext.REFERENCE_TYPE_EMBEDDED);
599            }
600    
601            protected void exportLayoutIconImage(
602                            PortletDataContext portletDataContext, Layout layout,
603                            Element layoutElement)
604                    throws Exception {
605    
606                    Image image = ImageLocalServiceUtil.getImage(layout.getIconImageId());
607    
608                    if (image != null) {
609                            String iconPath = ExportImportPathUtil.getModelPath(
610                                    portletDataContext.getScopeGroupId(), Image.class.getName(),
611                                    image.getImageId());
612    
613                            Element iconImagePathElement = layoutElement.addElement(
614                                    "icon-image-path");
615    
616                            iconImagePathElement.addText(iconPath);
617    
618                            portletDataContext.addZipEntry(iconPath, image.getTextObj());
619                    }
620            }
621    
622            protected void exportLinkedLayout(
623                            PortletDataContext portletDataContext, Layout layout,
624                            Element layoutElement)
625                    throws Exception {
626    
627                    UnicodeProperties typeSettingsProperties =
628                            layout.getTypeSettingsProperties();
629    
630                    long linkToLayoutId = GetterUtil.getLong(
631                            typeSettingsProperties.getProperty(
632                                    "linkToLayoutId", StringPool.BLANK));
633    
634                    if (linkToLayoutId > 0) {
635                            try {
636                                    Layout linkedToLayout = LayoutLocalServiceUtil.getLayout(
637                                            portletDataContext.getScopeGroupId(),
638                                            layout.isPrivateLayout(), linkToLayoutId);
639    
640                                    StagedModelDataHandlerUtil.exportReferenceStagedModel(
641                                            portletDataContext, layout, linkedToLayout,
642                                            PortletDataContext.REFERENCE_TYPE_STRONG);
643    
644                                    layoutElement.addAttribute(
645                                            "linked-to-layout-uuid", linkedToLayout.getUuid());
646                            }
647                            catch (NoSuchLayoutException nsle) {
648                            }
649                    }
650            }
651    
652            protected void exportTheme(
653                            PortletDataContext portletDataContext, Layout layout)
654                    throws Exception {
655    
656                    boolean exportThemeSettings = MapUtil.getBoolean(
657                            portletDataContext.getParameterMap(),
658                            PortletDataHandlerKeys.THEME_REFERENCE);
659    
660                    if (_log.isDebugEnabled()) {
661                            _log.debug("Export theme settings " + exportThemeSettings);
662                    }
663    
664                    if (exportThemeSettings &&
665                            !portletDataContext.isPerformDirectBinaryImport() &&
666                            !layout.isInheritLookAndFeel()) {
667    
668                            StagedTheme stagedTheme = new StagedTheme(layout.getTheme());
669    
670                            Element layoutElement = portletDataContext.getExportDataElement(
671                                    layout);
672    
673                            portletDataContext.addReferenceElement(
674                                    layout, layoutElement, stagedTheme,
675                                    PortletDataContext.REFERENCE_TYPE_DEPENDENCY, true);
676                    }
677            }
678    
679            protected Object[] extractFriendlyURLInfo(Layout layout) {
680                    if (!layout.isTypeURL()) {
681                            return null;
682                    }
683    
684                    UnicodeProperties typeSettings = layout.getTypeSettingsProperties();
685    
686                    String url = GetterUtil.getString(typeSettings.getProperty("url"));
687    
688                    String friendlyURLPrivateGroupPath =
689                            PropsValues.LAYOUT_FRIENDLY_URL_PRIVATE_GROUP_SERVLET_MAPPING;
690                    String friendlyURLPrivateUserPath =
691                            PropsValues.LAYOUT_FRIENDLY_URL_PRIVATE_USER_SERVLET_MAPPING;
692                    String friendlyURLPublicPath =
693                            PropsValues.LAYOUT_FRIENDLY_URL_PUBLIC_SERVLET_MAPPING;
694    
695                    if (!url.startsWith(friendlyURLPrivateGroupPath) &&
696                            !url.startsWith(friendlyURLPrivateUserPath) &&
697                            !url.startsWith(friendlyURLPublicPath)) {
698    
699                            return null;
700                    }
701    
702                    int x = url.indexOf(CharPool.SLASH, 1);
703    
704                    if (x == -1) {
705                            return null;
706                    }
707    
708                    int y = url.indexOf(CharPool.SLASH, x + 1);
709    
710                    if (y == -1) {
711                            return null;
712                    }
713    
714                    return new Object[] {url.substring(x, y), url, x, y};
715            }
716    
717            protected void fixExportTypeSettings(Layout layout) throws Exception {
718                    Object[] friendlyURLInfo = extractFriendlyURLInfo(layout);
719    
720                    if (friendlyURLInfo == null) {
721                            return;
722                    }
723    
724                    String friendlyURL = (String)friendlyURLInfo[0];
725    
726                    Group group = layout.getGroup();
727    
728                    String groupFriendlyURL = group.getFriendlyURL();
729    
730                    if (!friendlyURL.equals(groupFriendlyURL)) {
731                            return;
732                    }
733    
734                    UnicodeProperties typeSettings = layout.getTypeSettingsProperties();
735    
736                    String url = (String)friendlyURLInfo[1];
737    
738                    int x = (Integer)friendlyURLInfo[2];
739                    int y = (Integer)friendlyURLInfo[3];
740    
741                    typeSettings.setProperty(
742                            "url",
743                            url.substring(0, x) + LayoutExporter.SAME_GROUP_FRIENDLY_URL +
744                                    url.substring(y));
745            }
746    
747            protected void fixImportTypeSettings(Layout layout) throws Exception {
748                    Object[] friendlyURLInfo = extractFriendlyURLInfo(layout);
749    
750                    if (friendlyURLInfo == null) {
751                            return;
752                    }
753    
754                    String friendlyURL = (String)friendlyURLInfo[0];
755    
756                    if (!friendlyURL.equals(LayoutExporter.SAME_GROUP_FRIENDLY_URL)) {
757                            return;
758                    }
759    
760                    Group group = layout.getGroup();
761    
762                    UnicodeProperties typeSettings = layout.getTypeSettingsProperties();
763    
764                    String url = (String)friendlyURLInfo[1];
765    
766                    int x = (Integer)friendlyURLInfo[2];
767                    int y = (Integer)friendlyURLInfo[3];
768    
769                    typeSettings.setProperty(
770                            "url",
771                            url.substring(0, x) + group.getFriendlyURL() + url.substring(y));
772            }
773    
774            protected String getUniqueFriendlyURL(
775                            PortletDataContext portletDataContext, Layout existingLayout,
776                            String friendlyURL)
777                    throws SystemException {
778    
779                    for (int i = 1;; i++) {
780                            Layout duplicateFriendlyURLLayout =
781                                    LayoutLocalServiceUtil.fetchLayoutByFriendlyURL(
782                                            portletDataContext.getGroupId(),
783                                            portletDataContext.isPrivateLayout(), friendlyURL);
784    
785                            if ((duplicateFriendlyURLLayout == null) ||
786                                    (duplicateFriendlyURLLayout.getPlid() ==
787                                            existingLayout.getPlid())) {
788    
789                                    break;
790                            }
791    
792                            friendlyURL = friendlyURL + i;
793                    }
794    
795                    return friendlyURL;
796            }
797    
798            protected void importJournalArticle(
799                            PortletDataContext portletDataContext, Layout layout)
800                    throws Exception {
801    
802                    UnicodeProperties typeSettingsProperties =
803                            layout.getTypeSettingsProperties();
804    
805                    String articleId = typeSettingsProperties.getProperty(
806                            "article-id", StringPool.BLANK);
807    
808                    if (Validator.isNull(articleId)) {
809                            return;
810                    }
811    
812                    List<Element> referenceDataElements =
813                            portletDataContext.getReferenceDataElements(
814                                    layout, JournalArticle.class);
815    
816                    if (!referenceDataElements.isEmpty()) {
817                            StagedModelDataHandlerUtil.importReferenceStagedModel(
818                                    portletDataContext, referenceDataElements.get(0));
819                    }
820    
821                    Map<String, String> articleIds =
822                            (Map<String, String>)portletDataContext.getNewPrimaryKeysMap(
823                                    JournalArticle.class + ".articleId");
824    
825                    articleId = MapUtil.getString(articleIds, articleId, articleId);
826    
827                    typeSettingsProperties.setProperty("article-id", articleId);
828    
829                    JournalContentSearchLocalServiceUtil.updateContentSearch(
830                            portletDataContext.getScopeGroupId(), layout.isPrivateLayout(),
831                            layout.getLayoutId(), StringPool.BLANK, articleId, true);
832            }
833    
834            protected void importLayoutFriendlyURLs(
835                            PortletDataContext portletDataContext, Layout layout)
836                    throws Exception {
837    
838                    List<Element> layoutFriendlyURLElements =
839                            portletDataContext.getReferenceDataElements(
840                                    layout, LayoutFriendlyURL.class);
841    
842                    for (Element layoutFriendlyURLElement : layoutFriendlyURLElements) {
843                            String layoutFriendlyURLPath =
844                                    layoutFriendlyURLElement.attributeValue("path");
845    
846                            LayoutFriendlyURL layoutFriendlyURL =
847                                    (LayoutFriendlyURL)portletDataContext.getZipEntryAsObject(
848                                            layoutFriendlyURLPath);
849    
850                            StagedModelDataHandlerUtil.importReferenceStagedModel(
851                                    portletDataContext, layoutFriendlyURL);
852                    }
853            }
854    
855            protected void importLayoutIconImage(
856                            PortletDataContext portletDataContext, Layout importedLayout,
857                            Element layoutElement)
858                    throws Exception {
859    
860                    String iconImagePath = layoutElement.elementText("icon-image-path");
861    
862                    byte[] iconBytes = portletDataContext.getZipEntryAsByteArray(
863                            iconImagePath);
864    
865                    if (ArrayUtil.isNotEmpty(iconBytes)) {
866                            importedLayout.setIconImage(true);
867    
868                            if (importedLayout.getIconImageId() == 0) {
869                                    long iconImageId = CounterLocalServiceUtil.increment();
870    
871                                    importedLayout.setIconImageId(iconImageId);
872                            }
873    
874                            ImageLocalServiceUtil.updateImage(
875                                    importedLayout.getIconImageId(), iconBytes);
876                    }
877            }
878    
879            protected void importLinkedLayout(
880                            PortletDataContext portletDataContext, Layout layout,
881                            Layout importedLayout, Element layoutElement,
882                            Map<Long, Layout> newLayoutsMap)
883                    throws Exception {
884    
885                    UnicodeProperties typeSettingsProperties =
886                            layout.getTypeSettingsProperties();
887    
888                    long linkToLayoutId = GetterUtil.getLong(
889                            typeSettingsProperties.getProperty(
890                                    "linkToLayoutId", StringPool.BLANK));
891    
892                    String linkedToLayoutUuid = layoutElement.attributeValue(
893                            "linked-to-layout-uuid");
894    
895                    if (linkToLayoutId <= 0) {
896                            updateTypeSettings(importedLayout, layout);
897    
898                            return;
899                    }
900    
901                    Element linkedToLayoutElement =
902                            portletDataContext.getReferenceDataElement(
903                                    layout, Layout.class, layout.getGroupId(), linkedToLayoutUuid);
904    
905                    if (linkedToLayoutElement != null) {
906                            String linkedToLayoutPath = linkedToLayoutElement.attributeValue(
907                                    "path");
908    
909                            Layout linkedToLayout =
910                                    (Layout)portletDataContext.getZipEntryAsObject(
911                                            linkedToLayoutPath);
912    
913                            StagedModelDataHandlerUtil.importReferenceStagedModel(
914                                    portletDataContext, linkedToLayout);
915    
916                            Layout importedLinkedLayout = newLayoutsMap.get(linkToLayoutId);
917    
918                            typeSettingsProperties.setProperty(
919                                    "privateLayout",
920                                    String.valueOf(importedLinkedLayout.isPrivateLayout()));
921                            typeSettingsProperties.setProperty(
922                                    "linkToLayoutId",
923                                    String.valueOf(importedLinkedLayout.getLayoutId()));
924                    }
925                    else {
926                            if (_log.isWarnEnabled()) {
927                                    StringBundler sb = new StringBundler(6);
928    
929                                    sb.append("Unable to link layout with friendly URL ");
930                                    sb.append(layout.getFriendlyURL());
931                                    sb.append(" and layout id ");
932                                    sb.append(layout.getLayoutId());
933                                    sb.append(" to layout with layout id ");
934                                    sb.append(linkToLayoutId);
935    
936                                    _log.warn(sb.toString());
937                            }
938                    }
939    
940                    updateTypeSettings(importedLayout, layout);
941            }
942    
943            protected void importTheme(
944                            PortletDataContext portletDataContext, Layout layout,
945                            Layout importedLayout)
946                    throws Exception {
947    
948                    boolean importThemeSettings = MapUtil.getBoolean(
949                            portletDataContext.getParameterMap(),
950                            PortletDataHandlerKeys.THEME_REFERENCE);
951    
952                    if (_log.isDebugEnabled()) {
953                            _log.debug("Import theme settings " + importThemeSettings);
954                    }
955    
956                    if (importThemeSettings) {
957                            importedLayout.setColorSchemeId(layout.getColorSchemeId());
958                            importedLayout.setCss(layout.getCss());
959                            importedLayout.setThemeId(layout.getThemeId());
960                            importedLayout.setWapColorSchemeId(layout.getWapColorSchemeId());
961                            importedLayout.setWapThemeId(layout.getWapThemeId());
962                    }
963                    else {
964                            importedLayout.setColorSchemeId(StringPool.BLANK);
965                            importedLayout.setCss(StringPool.BLANK);
966                            importedLayout.setThemeId(StringPool.BLANK);
967                            importedLayout.setWapColorSchemeId(StringPool.BLANK);
968                            importedLayout.setWapThemeId(StringPool.BLANK);
969                    }
970            }
971    
972            protected void initNewLayoutPermissions(
973                            long companyId, long groupId, long userId, Layout layout,
974                            Layout importedLayout, boolean privateLayout)
975                    throws Exception {
976    
977                    boolean addGroupPermissions = true;
978    
979                    Group group = importedLayout.getGroup();
980    
981                    if (privateLayout && group.isUser()) {
982                            addGroupPermissions = false;
983                    }
984    
985                    boolean addGuestPermissions = false;
986    
987                    if (!privateLayout || layout.isTypeControlPanel()) {
988                            addGuestPermissions = true;
989                    }
990    
991                    ResourceLocalServiceUtil.addResources(
992                            companyId, groupId, userId, Layout.class.getName(),
993                            importedLayout.getPlid(), false, addGroupPermissions,
994                            addGuestPermissions);
995            }
996    
997            protected void mergePortlets(
998                    Layout layout, String newTypeSettings, String portletsMergeMode) {
999    
1000                    try {
1001                            UnicodeProperties previousTypeSettingsProperties =
1002                                    layout.getTypeSettingsProperties();
1003    
1004                            LayoutTypePortlet previousLayoutType =
1005                                    (LayoutTypePortlet)layout.getLayoutType();
1006    
1007                            LayoutTemplate previousLayoutTemplate =
1008                                    previousLayoutType.getLayoutTemplate();
1009    
1010                            List<String> previousColumns = previousLayoutTemplate.getColumns();
1011    
1012                            UnicodeProperties newTypeSettingsProperties = new UnicodeProperties(
1013                                    true);
1014    
1015                            newTypeSettingsProperties.load(newTypeSettings);
1016    
1017                            String layoutTemplateId = newTypeSettingsProperties.getProperty(
1018                                    LayoutTypePortletConstants.LAYOUT_TEMPLATE_ID);
1019    
1020                            previousTypeSettingsProperties.setProperty(
1021                                    LayoutTypePortletConstants.LAYOUT_TEMPLATE_ID,
1022                                    layoutTemplateId);
1023    
1024                            String nestedColumnIds = newTypeSettingsProperties.getProperty(
1025                                    LayoutTypePortletConstants.NESTED_COLUMN_IDS);
1026    
1027                            if (Validator.isNotNull(nestedColumnIds)) {
1028                                    previousTypeSettingsProperties.setProperty(
1029                                            LayoutTypePortletConstants.NESTED_COLUMN_IDS,
1030                                            nestedColumnIds);
1031    
1032                                    String[] nestedColumnIdsArray = StringUtil.split(
1033                                            nestedColumnIds);
1034    
1035                                    for (String nestedColumnId : nestedColumnIdsArray) {
1036                                            String nestedColumnValue =
1037                                                    newTypeSettingsProperties.getProperty(nestedColumnId);
1038    
1039                                            previousTypeSettingsProperties.setProperty(
1040                                                    nestedColumnId, nestedColumnValue);
1041                                    }
1042                            }
1043    
1044                            LayoutTemplate newLayoutTemplate =
1045                                    LayoutTemplateLocalServiceUtil.getLayoutTemplate(
1046                                            layoutTemplateId, false, null);
1047    
1048                            String[] newPortletIds = new String[0];
1049    
1050                            for (String columnId : newLayoutTemplate.getColumns()) {
1051                                    String columnValue = newTypeSettingsProperties.getProperty(
1052                                            columnId);
1053    
1054                                    String[] portletIds = StringUtil.split(columnValue);
1055    
1056                                    if (!previousColumns.contains(columnId)) {
1057                                            newPortletIds = ArrayUtil.append(newPortletIds, portletIds);
1058                                    }
1059                                    else {
1060                                            String[] previousPortletIds = StringUtil.split(
1061                                                    previousTypeSettingsProperties.getProperty(columnId));
1062    
1063                                            portletIds = appendPortletIds(
1064                                                    previousPortletIds, portletIds, portletsMergeMode);
1065    
1066                                            previousTypeSettingsProperties.setProperty(
1067                                                    columnId, StringUtil.merge(portletIds));
1068                                    }
1069                            }
1070    
1071                            // Add portlets in non-existent column to the first column
1072    
1073                            String columnId = previousColumns.get(0);
1074    
1075                            String[] portletIds = StringUtil.split(
1076                                    previousTypeSettingsProperties.getProperty(columnId));
1077    
1078                            appendPortletIds(portletIds, newPortletIds, portletsMergeMode);
1079    
1080                            previousTypeSettingsProperties.setProperty(
1081                                    columnId, StringUtil.merge(portletIds));
1082    
1083                            layout.setTypeSettings(previousTypeSettingsProperties.toString());
1084                    }
1085                    catch (IOException ioe) {
1086                            layout.setTypeSettings(newTypeSettings);
1087                    }
1088            }
1089    
1090            protected void populateElementLayoutMetadata(
1091                            Element layoutElement, Layout layout, LayoutRevision layoutRevision)
1092                    throws Exception {
1093    
1094                    if (layoutRevision != null) {
1095                            layoutElement.addAttribute(
1096                                    "layout-revision-id",
1097                                    String.valueOf(layoutRevision.getLayoutRevisionId()));
1098                            layoutElement.addAttribute(
1099                                    "layout-branch-id",
1100                                    String.valueOf(layoutRevision.getLayoutBranchId()));
1101    
1102                            LayoutBranch layoutBranch = layoutRevision.getLayoutBranch();
1103    
1104                            layoutElement.addAttribute(
1105                                    "layout-branch-name", String.valueOf(layoutBranch.getName()));
1106                    }
1107    
1108                    layoutElement.addAttribute("layout-uuid", layout.getUuid());
1109                    layoutElement.addAttribute(
1110                            "layout-id", String.valueOf(layout.getLayoutId()));
1111    
1112                    String layoutPrototypeUuid = layout.getLayoutPrototypeUuid();
1113    
1114                    if (Validator.isNotNull(layoutPrototypeUuid)) {
1115                            LayoutPrototype layoutPrototype =
1116                                    LayoutPrototypeLocalServiceUtil.
1117                                            getLayoutPrototypeByUuidAndCompanyId(
1118                                                    layoutPrototypeUuid, layout.getCompanyId());
1119    
1120                            layoutElement.addAttribute(
1121                                    "layout-prototype-uuid", layoutPrototypeUuid);
1122                            layoutElement.addAttribute(
1123                                    "layout-prototype-name",
1124                                    layoutPrototype.getName(LocaleUtil.getDefault()));
1125                    }
1126            }
1127    
1128            protected void updateTypeSettings(Layout importedLayout, Layout layout)
1129                    throws PortalException, SystemException {
1130    
1131                    long groupId = layout.getGroupId();
1132    
1133                    try {
1134                            LayoutTypePortlet importedLayoutType =
1135                                    (LayoutTypePortlet)importedLayout.getLayoutType();
1136    
1137                            List<String> importedPortletIds =
1138                                    importedLayoutType.getPortletIds();
1139    
1140                            layout.setGroupId(importedLayout.getGroupId());
1141    
1142                            LayoutTypePortlet layoutType =
1143                                    (LayoutTypePortlet)layout.getLayoutType();
1144    
1145                            importedPortletIds.removeAll(layoutType.getPortletIds());
1146    
1147                            if (!importedPortletIds.isEmpty()) {
1148                                    PortletLocalServiceUtil.deletePortlets(
1149                                            importedLayout.getCompanyId(),
1150                                            importedPortletIds.toArray(
1151                                                    new String[importedPortletIds.size()]),
1152                                            importedLayout.getPlid());
1153                            }
1154    
1155                            importedLayout.setTypeSettings(layout.getTypeSettings());
1156                    }
1157                    finally {
1158                            layout.setGroupId(groupId);
1159                    }
1160            }
1161    
1162            private static Log _log = LogFactoryUtil.getLog(
1163                    LayoutStagedModelDataHandler.class);
1164    
1165    }