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