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