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, layoutElement);
215                    }
216                    else if (layout.isTypeLinkToLayout()) {
217                            exportLinkedLayout(portletDataContext, layout, layoutElement);
218                    }
219    
220                    fixExportTypeSettings(layout);
221    
222                    portletDataContext.addClassedModel(
223                            layoutElement, ExportImportPathUtil.getModelPath(layout), layout,
224                            LayoutPortletDataHandler.NAMESPACE);
225            }
226    
227            @Override
228            protected void doImportStagedModel(
229                            PortletDataContext portletDataContext, Layout layout)
230                    throws Exception {
231    
232                    long groupId = portletDataContext.getGroupId();
233                    long userId = portletDataContext.getUserId(layout.getUserUuid());
234    
235                    Element layoutElement =
236                            portletDataContext.getImportDataStagedModelElement(layout);
237    
238                    String layoutUuid = GetterUtil.getString(
239                            layoutElement.attributeValue("layout-uuid"));
240    
241                    long layoutId = GetterUtil.getInteger(
242                            layoutElement.attributeValue("layout-id"));
243    
244                    long oldLayoutId = layoutId;
245    
246                    boolean privateLayout = portletDataContext.isPrivateLayout();
247    
248                    Map<Long, Layout> newLayoutsMap =
249                            (Map<Long, Layout>)portletDataContext.getNewPrimaryKeysMap(
250                                    Layout.class + ".layout");
251    
252                    String action = layoutElement.attributeValue("action");
253    
254                    if (action.equals(Constants.DELETE)) {
255                            Layout deletingLayout =
256                                    LayoutLocalServiceUtil.fetchLayoutByUuidAndGroupId(
257                                            layoutUuid, groupId, privateLayout);
258    
259                            if (layout != null) {
260                                    newLayoutsMap.put(oldLayoutId, layout);
261    
262                                    ServiceContext serviceContext =
263                                            ServiceContextThreadLocal.getServiceContext();
264    
265                                    LayoutLocalServiceUtil.deleteLayout(
266                                            deletingLayout, false, serviceContext);
267                            }
268    
269                            return;
270                    }
271    
272                    Layout existingLayout = null;
273                    Layout importedLayout = null;
274    
275                    String friendlyURL = layout.getFriendlyURL();
276    
277                    String layoutsImportMode = MapUtil.getString(
278                            portletDataContext.getParameterMap(),
279                            PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE,
280                            PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE_MERGE_BY_LAYOUT_UUID);
281    
282                    if (layoutsImportMode.equals(
283                                    PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE_ADD_AS_NEW)) {
284    
285                            layoutId = LayoutLocalServiceUtil.getNextLayoutId(
286                                    groupId, privateLayout);
287                            friendlyURL = StringPool.SLASH + layoutId;
288                    }
289                    else if (layoutsImportMode.equals(
290                                            PortletDataHandlerKeys.
291                                                    LAYOUTS_IMPORT_MODE_MERGE_BY_LAYOUT_NAME)) {
292    
293                            Locale locale = LocaleUtil.getSiteDefault();
294    
295                            String localizedName = layout.getName(locale);
296    
297                            List<Layout> previousLayouts = LayoutLocalServiceUtil.getLayouts(
298                                    groupId, privateLayout);
299    
300                            for (Layout curLayout : previousLayouts) {
301                                    if (localizedName.equals(curLayout.getName(locale)) ||
302                                            friendlyURL.equals(curLayout.getFriendlyURL())) {
303    
304                                            existingLayout = curLayout;
305    
306                                            break;
307                                    }
308                            }
309    
310                            if (existingLayout == null) {
311                                    layoutId = LayoutLocalServiceUtil.getNextLayoutId(
312                                            groupId, privateLayout);
313                            }
314                    }
315                    else if (layoutsImportMode.equals(
316                                            PortletDataHandlerKeys.
317                                                    LAYOUTS_IMPORT_MODE_CREATED_FROM_PROTOTYPE)) {
318    
319                            existingLayout = LayoutLocalServiceUtil.fetchLayoutByUuidAndGroupId(
320                                    layout.getUuid(), groupId, privateLayout);
321    
322                            if (SitesUtil.isLayoutModifiedSinceLastMerge(existingLayout)) {
323                                    newLayoutsMap.put(oldLayoutId, existingLayout);
324    
325                                    return;
326                            }
327    
328                            LayoutFriendlyURL layoutFriendlyURL =
329                                    LayoutFriendlyURLLocalServiceUtil.fetchFirstLayoutFriendlyURL(
330                                            groupId, privateLayout, friendlyURL);
331    
332                            if ((layoutFriendlyURL != null) && (existingLayout == null)) {
333                                    Layout mergeFailFriendlyURLLayout =
334                                            LayoutLocalServiceUtil.getLayout(
335                                                    layoutFriendlyURL.getPlid());
336    
337                                    SitesUtil.addMergeFailFriendlyURLLayout(
338                                            mergeFailFriendlyURLLayout);
339    
340                                    return;
341                            }
342                    }
343                    else {
344    
345                            // The default behaviour of import mode is
346                            // PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE_MERGE_BY_LAYOUT_UUID
347    
348                            existingLayout = LayoutLocalServiceUtil.fetchLayoutByUuidAndGroupId(
349                                    layout.getUuid(), groupId, privateLayout);
350    
351                            if (existingLayout == null) {
352                                    existingLayout =
353                                            LayoutLocalServiceUtil.fetchLayoutByFriendlyURL(
354                                                    groupId, privateLayout, friendlyURL);
355                            }
356    
357                            if (existingLayout == null) {
358                                    layoutId = LayoutLocalServiceUtil.getNextLayoutId(
359                                            groupId, privateLayout);
360                            }
361                    }
362    
363                    if (_log.isDebugEnabled()) {
364                            StringBundler sb = new StringBundler(7);
365    
366                            sb.append("Layout with {groupId=");
367                            sb.append(groupId);
368                            sb.append(",privateLayout=");
369                            sb.append(privateLayout);
370                            sb.append(",layoutId=");
371                            sb.append(layoutId);
372    
373                            if (existingLayout == null) {
374                                    sb.append("} does not exist");
375    
376                                    _log.debug(sb.toString());
377                            }
378                            else {
379                                    sb.append("} exists");
380    
381                                    _log.debug(sb.toString());
382                            }
383                    }
384    
385                    if (existingLayout == null) {
386                            long plid = CounterLocalServiceUtil.increment();
387    
388                            importedLayout = LayoutLocalServiceUtil.createLayout(plid);
389    
390                            if (layoutsImportMode.equals(
391                                            PortletDataHandlerKeys.
392                                                    LAYOUTS_IMPORT_MODE_CREATED_FROM_PROTOTYPE)) {
393    
394                                    importedLayout.setSourcePrototypeLayoutUuid(layout.getUuid());
395    
396                                    layoutId = LayoutLocalServiceUtil.getNextLayoutId(
397                                            groupId, privateLayout);
398                            }
399                            else {
400                                    importedLayout.setCreateDate(layout.getCreateDate());
401                                    importedLayout.setModifiedDate(layout.getModifiedDate());
402                                    importedLayout.setLayoutPrototypeUuid(
403                                            layout.getLayoutPrototypeUuid());
404                                    importedLayout.setLayoutPrototypeLinkEnabled(
405                                            layout.isLayoutPrototypeLinkEnabled());
406                                    importedLayout.setSourcePrototypeLayoutUuid(
407                                            layout.getSourcePrototypeLayoutUuid());
408                            }
409    
410                            importedLayout.setUuid(layout.getUuid());
411                            importedLayout.setGroupId(groupId);
412                            importedLayout.setPrivateLayout(privateLayout);
413                            importedLayout.setLayoutId(layoutId);
414    
415                            initNewLayoutPermissions(
416                                    portletDataContext.getCompanyId(), groupId, userId, layout,
417                                    importedLayout, privateLayout);
418    
419                            LayoutSet layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
420                                    groupId, privateLayout);
421    
422                            importedLayout.setLayoutSet(layoutSet);
423                    }
424                    else {
425                            importedLayout = existingLayout;
426                    }
427    
428                    portletDataContext.setPlid(importedLayout.getPlid());
429                    portletDataContext.setOldPlid(layout.getPlid());
430    
431                    newLayoutsMap.put(oldLayoutId, importedLayout);
432    
433                    long parentLayoutId = layout.getParentLayoutId();
434    
435                    String parentLayoutUuid = GetterUtil.getString(
436                            layoutElement.attributeValue("parent-layout-uuid"));
437    
438                    Element parentLayoutElement =
439                            portletDataContext.getReferenceDataElement(
440                                    layout, Layout.class, layout.getGroupId(), parentLayoutUuid);
441    
442                    if ((parentLayoutId != LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) &&
443                            (parentLayoutElement != null)) {
444    
445                            String parentLayoutPath = parentLayoutElement.attributeValue(
446                                    "path");
447    
448                            Layout parentLayout =
449                                    (Layout)portletDataContext.getZipEntryAsObject(
450                                            parentLayoutPath);
451    
452                            StagedModelDataHandlerUtil.importStagedModel(
453                                    portletDataContext, parentLayout);
454    
455                            Layout importedParentLayout = newLayoutsMap.get(parentLayoutId);
456    
457                            parentLayoutId = importedParentLayout.getLayoutId();
458                    }
459    
460                    if (_log.isDebugEnabled()) {
461                            StringBundler sb = new StringBundler(4);
462    
463                            sb.append("Importing layout with layout id ");
464                            sb.append(layoutId);
465                            sb.append(" and parent layout id ");
466                            sb.append(parentLayoutId);
467    
468                            _log.debug(sb.toString());
469                    }
470    
471                    importedLayout.setCompanyId(portletDataContext.getCompanyId());
472                    importedLayout.setParentLayoutId(parentLayoutId);
473                    importedLayout.setName(layout.getName());
474                    importedLayout.setTitle(layout.getTitle());
475                    importedLayout.setDescription(layout.getDescription());
476                    importedLayout.setKeywords(layout.getKeywords());
477                    importedLayout.setRobots(layout.getRobots());
478                    importedLayout.setType(layout.getType());
479    
480                    String portletsMergeMode = MapUtil.getString(
481                            portletDataContext.getParameterMap(),
482                            PortletDataHandlerKeys.PORTLETS_MERGE_MODE,
483                            PortletDataHandlerKeys.PORTLETS_MERGE_MODE_REPLACE);
484    
485                    if (layout.isTypeArticle()) {
486                            importJournalArticle(portletDataContext, layout, layoutElement);
487    
488                            updateTypeSettings(importedLayout, layout);
489                    }
490                    else if (layout.isTypePortlet() &&
491                                     Validator.isNotNull(layout.getTypeSettings()) &&
492                                     !portletsMergeMode.equals(
493                                             PortletDataHandlerKeys.PORTLETS_MERGE_MODE_REPLACE)) {
494    
495                            mergePortlets(
496                                    importedLayout, layout.getTypeSettings(), portletsMergeMode);
497                    }
498                    else if (layout.isTypeLinkToLayout()) {
499                            importLinkedLayout(
500                                    portletDataContext, layout, importedLayout, layoutElement,
501                                    newLayoutsMap);
502                    }
503                    else {
504                            updateTypeSettings(importedLayout, layout);
505                    }
506    
507                    importedLayout.setHidden(layout.isHidden());
508                    importedLayout.setFriendlyURL(
509                            getUniqueFriendlyURL(
510                                    portletDataContext, importedLayout, friendlyURL));
511                    importedLayout.setIconImage(false);
512    
513                    if (layout.isIconImage()) {
514                            importLayoutIconImage(
515                                    portletDataContext, importedLayout, layoutElement);
516                    }
517                    else {
518                            ImageLocalServiceUtil.deleteImage(importedLayout.getIconImageId());
519                    }
520    
521                    boolean importThemeSettings = MapUtil.getBoolean(
522                            portletDataContext.getParameterMap(),
523                            PortletDataHandlerKeys.THEME_REFERENCE);
524    
525                    if (importThemeSettings) {
526                            importedLayout.setThemeId(layout.getThemeId());
527                            importedLayout.setColorSchemeId(layout.getColorSchemeId());
528                    }
529                    else {
530                            importedLayout.setThemeId(StringPool.BLANK);
531                            importedLayout.setColorSchemeId(StringPool.BLANK);
532                    }
533    
534                    importedLayout.setWapThemeId(layout.getWapThemeId());
535                    importedLayout.setWapColorSchemeId(layout.getWapColorSchemeId());
536                    importedLayout.setCss(layout.getCss());
537                    importedLayout.setPriority(layout.getPriority());
538                    importedLayout.setLayoutPrototypeUuid(layout.getLayoutPrototypeUuid());
539                    importedLayout.setLayoutPrototypeLinkEnabled(
540                            layout.isLayoutPrototypeLinkEnabled());
541    
542                    StagingUtil.updateLastImportSettings(
543                            layoutElement, importedLayout, portletDataContext);
544    
545                    fixImportTypeSettings(importedLayout);
546    
547                    LayoutLocalServiceUtil.updateLayout(importedLayout);
548    
549                    LayoutSetLocalServiceUtil.updatePageCount(groupId, privateLayout);
550    
551                    List<Layout> newLayouts = portletDataContext.getNewLayouts();
552    
553                    newLayouts.add(importedLayout);
554    
555                    Map<Long, Long> layoutPlids =
556                            (Map<Long, Long>)portletDataContext.getNewPrimaryKeysMap(
557                                    Layout.class);
558    
559                    layoutPlids.put(layout.getPlid(), importedLayout.getPlid());
560    
561                    importLayoutFriendlyURLs(portletDataContext, layout);
562    
563                    portletDataContext.importClassedModel(
564                            layout, importedLayout, LayoutPortletDataHandler.NAMESPACE);
565            }
566    
567            protected void exportJournalArticle(
568                            PortletDataContext portletDataContext, Layout layout,
569                            Element layoutElement)
570                    throws Exception {
571    
572                    UnicodeProperties typeSettingsProperties =
573                            layout.getTypeSettingsProperties();
574    
575                    String articleId = typeSettingsProperties.getProperty(
576                            "article-id", StringPool.BLANK);
577    
578                    long articleGroupId = layout.getGroupId();
579    
580                    if (Validator.isNull(articleId)) {
581                            if (_log.isWarnEnabled()) {
582                                    _log.warn(
583                                            "No article id found in typeSettings of layout " +
584                                                    layout.getPlid());
585                            }
586                    }
587    
588                    JournalArticle article = null;
589    
590                    try {
591                            article = JournalArticleLocalServiceUtil.getLatestArticle(
592                                    articleGroupId, articleId, WorkflowConstants.STATUS_APPROVED);
593                    }
594                    catch (NoSuchArticleException nsae) {
595                            if (_log.isWarnEnabled()) {
596                                    StringBundler sb = new StringBundler(4);
597    
598                                    sb.append("No approved article found with group id ");
599                                    sb.append(articleGroupId);
600                                    sb.append(" and layout id ");
601                                    sb.append(articleId);
602    
603                                    _log.warn(sb.toString());
604                            }
605                    }
606    
607                    if (article == null) {
608                            return;
609                    }
610    
611                    StagedModelDataHandlerUtil.exportReferenceStagedModel(
612                            portletDataContext, layout, article,
613                            PortletDataContext.REFERENCE_TYPE_EMBEDDED);
614            }
615    
616            protected void exportLayoutIconImage(
617                            PortletDataContext portletDataContext, Layout layout,
618                            Element layoutElement)
619                    throws Exception {
620    
621                    Image image = ImageLocalServiceUtil.getImage(layout.getIconImageId());
622    
623                    if (image != null) {
624                            String iconPath = ExportImportPathUtil.getModelPath(
625                                    portletDataContext.getScopeGroupId(), Image.class.getName(),
626                                    image.getImageId());
627    
628                            Element iconImagePathElement = layoutElement.addElement(
629                                    "icon-image-path");
630    
631                            iconImagePathElement.addText(iconPath);
632    
633                            portletDataContext.addZipEntry(iconPath, image.getTextObj());
634                    }
635            }
636    
637            protected void exportLinkedLayout(
638                            PortletDataContext portletDataContext, Layout layout,
639                            Element layoutElement)
640                    throws Exception {
641    
642                    UnicodeProperties typeSettingsProperties =
643                            layout.getTypeSettingsProperties();
644    
645                    long linkToLayoutId = GetterUtil.getLong(
646                            typeSettingsProperties.getProperty(
647                                    "linkToLayoutId", StringPool.BLANK));
648    
649                    if (linkToLayoutId > 0) {
650                            try {
651                                    Layout linkedToLayout = LayoutLocalServiceUtil.getLayout(
652                                            portletDataContext.getScopeGroupId(),
653                                            layout.isPrivateLayout(), linkToLayoutId);
654    
655                                    StagedModelDataHandlerUtil.exportReferenceStagedModel(
656                                            portletDataContext, layout, linkedToLayout,
657                                            PortletDataContext.REFERENCE_TYPE_STRONG);
658    
659                                    layoutElement.addAttribute(
660                                            "linked-to-layout-uuid", linkedToLayout.getUuid());
661                            }
662                            catch (NoSuchLayoutException nsle) {
663                            }
664                    }
665            }
666    
667            protected Object[] extractFriendlyURLInfo(Layout layout) {
668                    if (!layout.isTypeURL()) {
669                            return null;
670                    }
671    
672                    UnicodeProperties typeSettings = layout.getTypeSettingsProperties();
673    
674                    String url = GetterUtil.getString(typeSettings.getProperty("url"));
675    
676                    String friendlyURLPrivateGroupPath =
677                            PropsValues.LAYOUT_FRIENDLY_URL_PRIVATE_GROUP_SERVLET_MAPPING;
678                    String friendlyURLPrivateUserPath =
679                            PropsValues.LAYOUT_FRIENDLY_URL_PRIVATE_USER_SERVLET_MAPPING;
680                    String friendlyURLPublicPath =
681                            PropsValues.LAYOUT_FRIENDLY_URL_PUBLIC_SERVLET_MAPPING;
682    
683                    if (!url.startsWith(friendlyURLPrivateGroupPath) &&
684                            !url.startsWith(friendlyURLPrivateUserPath) &&
685                            !url.startsWith(friendlyURLPublicPath)) {
686    
687                            return null;
688                    }
689    
690                    int x = url.indexOf(CharPool.SLASH, 1);
691    
692                    if (x == -1) {
693                            return null;
694                    }
695    
696                    int y = url.indexOf(CharPool.SLASH, x + 1);
697    
698                    if (y == -1) {
699                            return null;
700                    }
701    
702                    return new Object[] {url.substring(x, y), url, x, y};
703            }
704    
705            protected void fixExportTypeSettings(Layout layout) throws Exception {
706                    Object[] friendlyURLInfo = extractFriendlyURLInfo(layout);
707    
708                    if (friendlyURLInfo == null) {
709                            return;
710                    }
711    
712                    String friendlyURL = (String)friendlyURLInfo[0];
713    
714                    Group group = layout.getGroup();
715    
716                    String groupFriendlyURL = group.getFriendlyURL();
717    
718                    if (!friendlyURL.equals(groupFriendlyURL)) {
719                            return;
720                    }
721    
722                    UnicodeProperties typeSettings = layout.getTypeSettingsProperties();
723    
724                    String url = (String)friendlyURLInfo[1];
725    
726                    int x = (Integer)friendlyURLInfo[2];
727                    int y = (Integer)friendlyURLInfo[3];
728    
729                    typeSettings.setProperty(
730                            "url",
731                            url.substring(0, x) + LayoutExporter.SAME_GROUP_FRIENDLY_URL +
732                                    url.substring(y));
733            }
734    
735            protected void fixImportTypeSettings(Layout layout) throws Exception {
736                    Object[] friendlyURLInfo = extractFriendlyURLInfo(layout);
737    
738                    if (friendlyURLInfo == null) {
739                            return;
740                    }
741    
742                    String friendlyURL = (String)friendlyURLInfo[0];
743    
744                    if (!friendlyURL.equals(LayoutExporter.SAME_GROUP_FRIENDLY_URL)) {
745                            return;
746                    }
747    
748                    Group group = layout.getGroup();
749    
750                    UnicodeProperties typeSettings = layout.getTypeSettingsProperties();
751    
752                    String url = (String)friendlyURLInfo[1];
753    
754                    int x = (Integer)friendlyURLInfo[2];
755                    int y = (Integer)friendlyURLInfo[3];
756    
757                    typeSettings.setProperty(
758                            "url",
759                            url.substring(0, x) + group.getFriendlyURL() + url.substring(y));
760            }
761    
762            protected String getUniqueFriendlyURL(
763                            PortletDataContext portletDataContext, Layout existingLayout,
764                            String friendlyURL)
765                    throws SystemException {
766    
767                    for (int i = 1;; i++) {
768                            Layout duplicateFriendlyURLLayout =
769                                    LayoutLocalServiceUtil.fetchLayoutByFriendlyURL(
770                                            portletDataContext.getGroupId(),
771                                            portletDataContext.isPrivateLayout(), friendlyURL);
772    
773                            if ((duplicateFriendlyURLLayout == null) ||
774                                    (duplicateFriendlyURLLayout.getPlid() ==
775                                            existingLayout.getPlid())) {
776    
777                                    break;
778                            }
779    
780                            friendlyURL = friendlyURL + i;
781                    }
782    
783                    return friendlyURL;
784            }
785    
786            protected void importJournalArticle(
787                            PortletDataContext portletDataContext, Layout layout,
788                            Element layoutElement)
789                    throws Exception {
790    
791                    UnicodeProperties typeSettingsProperties =
792                            layout.getTypeSettingsProperties();
793    
794                    String articleId = typeSettingsProperties.getProperty(
795                            "article-id", StringPool.BLANK);
796    
797                    if (Validator.isNull(articleId)) {
798                            return;
799                    }
800    
801                    List<Element> referenceDataElements =
802                            portletDataContext.getReferenceDataElements(
803                                    layoutElement, JournalArticle.class);
804    
805                    if (!referenceDataElements.isEmpty()) {
806                            StagedModelDataHandlerUtil.importStagedModel(
807                                    portletDataContext, referenceDataElements.get(0));
808                    }
809    
810                    Map<String, String> articleIds =
811                            (Map<String, String>)portletDataContext.getNewPrimaryKeysMap(
812                                    JournalArticle.class + ".articleId");
813    
814                    articleId = MapUtil.getString(articleIds, articleId, articleId);
815    
816                    typeSettingsProperties.setProperty("article-id", articleId);
817    
818                    JournalContentSearchLocalServiceUtil.updateContentSearch(
819                            portletDataContext.getScopeGroupId(), layout.isPrivateLayout(),
820                            layout.getLayoutId(), StringPool.BLANK, articleId, true);
821            }
822    
823            protected void importLayoutFriendlyURLs(
824                            PortletDataContext portletDataContext, Layout layout)
825                    throws Exception {
826    
827                    List<Element> layoutFriendlyURLElements =
828                            portletDataContext.getReferenceDataElements(
829                                    layout, LayoutFriendlyURL.class);
830    
831                    for (Element layoutFriendlyURLElement : layoutFriendlyURLElements) {
832                            String layoutFriendlyURLPath =
833                                    layoutFriendlyURLElement.attributeValue("path");
834    
835                            LayoutFriendlyURL layoutFriendlyURL =
836                                    (LayoutFriendlyURL)portletDataContext.getZipEntryAsObject(
837                                            layoutFriendlyURLPath);
838    
839                            StagedModelDataHandlerUtil.importStagedModel(
840                                    portletDataContext, layoutFriendlyURL);
841                    }
842            }
843    
844            protected void importLayoutIconImage(
845                            PortletDataContext portletDataContext, Layout importedLayout,
846                            Element layoutElement)
847                    throws Exception {
848    
849                    String iconImagePath = layoutElement.elementText("icon-image-path");
850    
851                    byte[] iconBytes = portletDataContext.getZipEntryAsByteArray(
852                            iconImagePath);
853    
854                    if (ArrayUtil.isNotEmpty(iconBytes)) {
855                            importedLayout.setIconImage(true);
856    
857                            if (importedLayout.getIconImageId() == 0) {
858                                    long iconImageId = CounterLocalServiceUtil.increment();
859    
860                                    importedLayout.setIconImageId(iconImageId);
861                            }
862    
863                            ImageLocalServiceUtil.updateImage(
864                                    importedLayout.getIconImageId(), iconBytes);
865                    }
866            }
867    
868            protected void importLinkedLayout(
869                            PortletDataContext portletDataContext, Layout layout,
870                            Layout importedLayout, Element layoutElement,
871                            Map<Long, Layout> newLayoutsMap)
872                    throws Exception {
873    
874                    UnicodeProperties typeSettingsProperties =
875                            layout.getTypeSettingsProperties();
876    
877                    long linkToLayoutId = GetterUtil.getLong(
878                            typeSettingsProperties.getProperty(
879                                    "linkToLayoutId", StringPool.BLANK));
880    
881                    String linkedToLayoutUuid = layoutElement.attributeValue(
882                            "linked-to-layout-uuid");
883    
884                    if (linkToLayoutId <= 0) {
885                            updateTypeSettings(importedLayout, layout);
886    
887                            return;
888                    }
889    
890                    Element linkedToLayoutElement =
891                            portletDataContext.getReferenceDataElement(
892                                    layout, Layout.class, layout.getGroupId(), linkedToLayoutUuid);
893    
894                    if (linkedToLayoutElement != null) {
895                            String linkedToLayoutPath = linkedToLayoutElement.attributeValue(
896                                    "path");
897    
898                            Layout linkedToLayout =
899                                    (Layout)portletDataContext.getZipEntryAsObject(
900                                            linkedToLayoutPath);
901    
902                            StagedModelDataHandlerUtil.importStagedModel(
903                                    portletDataContext, linkedToLayout);
904    
905                            Layout importedLinkedLayout = newLayoutsMap.get(linkToLayoutId);
906    
907                            typeSettingsProperties.setProperty(
908                                    "privateLayout",
909                                    String.valueOf(importedLinkedLayout.isPrivateLayout()));
910                            typeSettingsProperties.setProperty(
911                                    "linkToLayoutId",
912                                    String.valueOf(importedLinkedLayout.getLayoutId()));
913                    }
914                    else {
915                            if (_log.isWarnEnabled()) {
916                                    StringBundler sb = new StringBundler(6);
917    
918                                    sb.append("Unable to link layout with friendly URL ");
919                                    sb.append(layout.getFriendlyURL());
920                                    sb.append(" and layout id ");
921                                    sb.append(layout.getLayoutId());
922                                    sb.append(" to layout with layout id ");
923                                    sb.append(linkToLayoutId);
924    
925                                    _log.warn(sb.toString());
926                            }
927                    }
928    
929                    updateTypeSettings(importedLayout, layout);
930            }
931    
932            protected void initNewLayoutPermissions(
933                            long companyId, long groupId, long userId, Layout layout,
934                            Layout importedLayout, boolean privateLayout)
935                    throws Exception {
936    
937                    boolean addGroupPermissions = true;
938    
939                    Group group = importedLayout.getGroup();
940    
941                    if (privateLayout && group.isUser()) {
942                            addGroupPermissions = false;
943                    }
944    
945                    boolean addGuestPermissions = false;
946    
947                    if (!privateLayout || layout.isTypeControlPanel()) {
948                            addGuestPermissions = true;
949                    }
950    
951                    ResourceLocalServiceUtil.addResources(
952                            companyId, groupId, userId, Layout.class.getName(),
953                            importedLayout.getPlid(), false, addGroupPermissions,
954                            addGuestPermissions);
955            }
956    
957            protected void mergePortlets(
958                    Layout layout, String newTypeSettings, String portletsMergeMode) {
959    
960                    try {
961                            UnicodeProperties previousTypeSettingsProperties =
962                                    layout.getTypeSettingsProperties();
963    
964                            LayoutTypePortlet previousLayoutType =
965                                    (LayoutTypePortlet)layout.getLayoutType();
966    
967                            LayoutTemplate previousLayoutTemplate =
968                                    previousLayoutType.getLayoutTemplate();
969    
970                            List<String> previousColumns = previousLayoutTemplate.getColumns();
971    
972                            UnicodeProperties newTypeSettingsProperties = new UnicodeProperties(
973                                    true);
974    
975                            newTypeSettingsProperties.load(newTypeSettings);
976    
977                            String layoutTemplateId = newTypeSettingsProperties.getProperty(
978                                    LayoutTypePortletConstants.LAYOUT_TEMPLATE_ID);
979    
980                            previousTypeSettingsProperties.setProperty(
981                                    LayoutTypePortletConstants.LAYOUT_TEMPLATE_ID,
982                                    layoutTemplateId);
983    
984                            String nestedColumnIds = newTypeSettingsProperties.getProperty(
985                                    LayoutTypePortletConstants.NESTED_COLUMN_IDS);
986    
987                            if (Validator.isNotNull(nestedColumnIds)) {
988                                    previousTypeSettingsProperties.setProperty(
989                                            LayoutTypePortletConstants.NESTED_COLUMN_IDS,
990                                            nestedColumnIds);
991    
992                                    String[] nestedColumnIdsArray = StringUtil.split(
993                                            nestedColumnIds);
994    
995                                    for (String nestedColumnId : nestedColumnIdsArray) {
996                                            String nestedColumnValue =
997                                                    newTypeSettingsProperties.getProperty(nestedColumnId);
998    
999                                            previousTypeSettingsProperties.setProperty(
1000                                                    nestedColumnId, nestedColumnValue);
1001                                    }
1002                            }
1003    
1004                            LayoutTemplate newLayoutTemplate =
1005                                    LayoutTemplateLocalServiceUtil.getLayoutTemplate(
1006                                            layoutTemplateId, false, null);
1007    
1008                            String[] newPortletIds = new String[0];
1009    
1010                            for (String columnId : newLayoutTemplate.getColumns()) {
1011                                    String columnValue = newTypeSettingsProperties.getProperty(
1012                                            columnId);
1013    
1014                                    String[] portletIds = StringUtil.split(columnValue);
1015    
1016                                    if (!previousColumns.contains(columnId)) {
1017                                            newPortletIds = ArrayUtil.append(newPortletIds, portletIds);
1018                                    }
1019                                    else {
1020                                            String[] previousPortletIds = StringUtil.split(
1021                                                    previousTypeSettingsProperties.getProperty(columnId));
1022    
1023                                            portletIds = appendPortletIds(
1024                                                    previousPortletIds, portletIds, portletsMergeMode);
1025    
1026                                            previousTypeSettingsProperties.setProperty(
1027                                                    columnId, StringUtil.merge(portletIds));
1028                                    }
1029                            }
1030    
1031                            // Add portlets in non-existent column to the first column
1032    
1033                            String columnId = previousColumns.get(0);
1034    
1035                            String[] portletIds = StringUtil.split(
1036                                    previousTypeSettingsProperties.getProperty(columnId));
1037    
1038                            appendPortletIds(portletIds, newPortletIds, portletsMergeMode);
1039    
1040                            previousTypeSettingsProperties.setProperty(
1041                                    columnId, StringUtil.merge(portletIds));
1042    
1043                            layout.setTypeSettings(previousTypeSettingsProperties.toString());
1044                    }
1045                    catch (IOException ioe) {
1046                            layout.setTypeSettings(newTypeSettings);
1047                    }
1048            }
1049    
1050            protected void populateElementLayoutMetadata(
1051                            Element layoutElement, Layout layout, LayoutRevision layoutRevision)
1052                    throws Exception {
1053    
1054                    if (layoutRevision != null) {
1055                            layoutElement.addAttribute(
1056                                    "layout-revision-id",
1057                                    String.valueOf(layoutRevision.getLayoutRevisionId()));
1058                            layoutElement.addAttribute(
1059                                    "layout-branch-id",
1060                                    String.valueOf(layoutRevision.getLayoutBranchId()));
1061    
1062                            LayoutBranch layoutBranch = layoutRevision.getLayoutBranch();
1063    
1064                            layoutElement.addAttribute(
1065                                    "layout-branch-name", String.valueOf(layoutBranch.getName()));
1066                    }
1067    
1068                    layoutElement.addAttribute("layout-uuid", layout.getUuid());
1069                    layoutElement.addAttribute(
1070                            "layout-id", String.valueOf(layout.getLayoutId()));
1071    
1072                    String layoutPrototypeUuid = layout.getLayoutPrototypeUuid();
1073    
1074                    if (Validator.isNotNull(layoutPrototypeUuid)) {
1075                            LayoutPrototype layoutPrototype =
1076                                    LayoutPrototypeLocalServiceUtil.
1077                                            getLayoutPrototypeByUuidAndCompanyId(
1078                                                    layoutPrototypeUuid, layout.getCompanyId());
1079    
1080                            layoutElement.addAttribute(
1081                                    "layout-prototype-uuid", layoutPrototypeUuid);
1082                            layoutElement.addAttribute(
1083                                    "layout-prototype-name",
1084                                    layoutPrototype.getName(LocaleUtil.getDefault()));
1085                    }
1086            }
1087    
1088            protected void updateTypeSettings(Layout importedLayout, Layout layout)
1089                    throws PortalException, SystemException {
1090    
1091                    long groupId = layout.getGroupId();
1092    
1093                    try {
1094                            LayoutTypePortlet importedLayoutType =
1095                                    (LayoutTypePortlet)importedLayout.getLayoutType();
1096    
1097                            List<String> importedPortletIds =
1098                                    importedLayoutType.getPortletIds();
1099    
1100                            layout.setGroupId(importedLayout.getGroupId());
1101    
1102                            LayoutTypePortlet layoutType =
1103                                    (LayoutTypePortlet)layout.getLayoutType();
1104    
1105                            importedPortletIds.removeAll(layoutType.getPortletIds());
1106    
1107                            if (!importedPortletIds.isEmpty()) {
1108                                    PortletLocalServiceUtil.deletePortlets(
1109                                            importedLayout.getCompanyId(),
1110                                            importedPortletIds.toArray(
1111                                                    new String[importedPortletIds.size()]),
1112                                            importedLayout.getPlid());
1113                            }
1114    
1115                            importedLayout.setTypeSettings(layout.getTypeSettings());
1116                    }
1117                    finally {
1118                            layout.setGroupId(groupId);
1119                    }
1120            }
1121    
1122            private static Log _log = LogFactoryUtil.getLog(
1123                    LayoutStagedModelDataHandler.class);
1124    
1125    }