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