001    /**
002     * Copyright (c) 2000-2012 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.portal.lar;
016    
017    import com.liferay.counter.service.CounterLocalServiceUtil;
018    import com.liferay.portal.LARFileException;
019    import com.liferay.portal.LARTypeException;
020    import com.liferay.portal.LayoutImportException;
021    import com.liferay.portal.NoSuchLayoutException;
022    import com.liferay.portal.NoSuchLayoutSetPrototypeException;
023    import com.liferay.portal.kernel.cluster.ClusterExecutorUtil;
024    import com.liferay.portal.kernel.cluster.ClusterRequest;
025    import com.liferay.portal.kernel.exception.PortalException;
026    import com.liferay.portal.kernel.exception.SystemException;
027    import com.liferay.portal.kernel.lar.ImportExportThreadLocal;
028    import com.liferay.portal.kernel.lar.PortletDataContext;
029    import com.liferay.portal.kernel.lar.PortletDataHandlerKeys;
030    import com.liferay.portal.kernel.lar.UserIdStrategy;
031    import com.liferay.portal.kernel.log.Log;
032    import com.liferay.portal.kernel.log.LogFactoryUtil;
033    import com.liferay.portal.kernel.search.Indexer;
034    import com.liferay.portal.kernel.search.IndexerRegistryUtil;
035    import com.liferay.portal.kernel.staging.StagingUtil;
036    import com.liferay.portal.kernel.util.ArrayUtil;
037    import com.liferay.portal.kernel.util.CharPool;
038    import com.liferay.portal.kernel.util.FileUtil;
039    import com.liferay.portal.kernel.util.GetterUtil;
040    import com.liferay.portal.kernel.util.LocaleUtil;
041    import com.liferay.portal.kernel.util.MapUtil;
042    import com.liferay.portal.kernel.util.MethodHandler;
043    import com.liferay.portal.kernel.util.MethodKey;
044    import com.liferay.portal.kernel.util.ReleaseInfo;
045    import com.liferay.portal.kernel.util.StringBundler;
046    import com.liferay.portal.kernel.util.StringPool;
047    import com.liferay.portal.kernel.util.StringUtil;
048    import com.liferay.portal.kernel.util.Time;
049    import com.liferay.portal.kernel.util.UnicodeProperties;
050    import com.liferay.portal.kernel.util.Validator;
051    import com.liferay.portal.kernel.xml.Attribute;
052    import com.liferay.portal.kernel.xml.Document;
053    import com.liferay.portal.kernel.xml.Element;
054    import com.liferay.portal.kernel.xml.Node;
055    import com.liferay.portal.kernel.xml.SAXReaderUtil;
056    import com.liferay.portal.kernel.zip.ZipReader;
057    import com.liferay.portal.kernel.zip.ZipReaderFactoryUtil;
058    import com.liferay.portal.model.Group;
059    import com.liferay.portal.model.Layout;
060    import com.liferay.portal.model.LayoutConstants;
061    import com.liferay.portal.model.LayoutSet;
062    import com.liferay.portal.model.LayoutSetPrototype;
063    import com.liferay.portal.model.LayoutTemplate;
064    import com.liferay.portal.model.LayoutTypePortlet;
065    import com.liferay.portal.model.LayoutTypePortletConstants;
066    import com.liferay.portal.model.Portlet;
067    import com.liferay.portal.model.PortletConstants;
068    import com.liferay.portal.model.Resource;
069    import com.liferay.portal.model.ResourceConstants;
070    import com.liferay.portal.model.Role;
071    import com.liferay.portal.model.RoleConstants;
072    import com.liferay.portal.model.User;
073    import com.liferay.portal.model.impl.ColorSchemeImpl;
074    import com.liferay.portal.security.permission.ActionKeys;
075    import com.liferay.portal.security.permission.PermissionCacheUtil;
076    import com.liferay.portal.service.GroupLocalServiceUtil;
077    import com.liferay.portal.service.ImageLocalServiceUtil;
078    import com.liferay.portal.service.LayoutLocalServiceUtil;
079    import com.liferay.portal.service.LayoutSetLocalServiceUtil;
080    import com.liferay.portal.service.LayoutSetPrototypeLocalServiceUtil;
081    import com.liferay.portal.service.LayoutTemplateLocalServiceUtil;
082    import com.liferay.portal.service.PermissionLocalServiceUtil;
083    import com.liferay.portal.service.PortletLocalServiceUtil;
084    import com.liferay.portal.service.ResourceLocalServiceUtil;
085    import com.liferay.portal.service.ResourcePermissionLocalServiceUtil;
086    import com.liferay.portal.service.RoleLocalServiceUtil;
087    import com.liferay.portal.service.ServiceContext;
088    import com.liferay.portal.service.ServiceContextThreadLocal;
089    import com.liferay.portal.service.persistence.LayoutUtil;
090    import com.liferay.portal.service.persistence.UserUtil;
091    import com.liferay.portal.servlet.filters.cache.CacheUtil;
092    import com.liferay.portal.theme.ThemeLoader;
093    import com.liferay.portal.theme.ThemeLoaderFactory;
094    import com.liferay.portal.util.PortalUtil;
095    import com.liferay.portal.util.PortletKeys;
096    import com.liferay.portal.util.PropsValues;
097    import com.liferay.portlet.journal.lar.JournalPortletDataHandlerImpl;
098    import com.liferay.portlet.journal.model.JournalArticle;
099    import com.liferay.portlet.journal.service.JournalContentSearchLocalServiceUtil;
100    import com.liferay.portlet.journalcontent.util.JournalContentUtil;
101    import com.liferay.portlet.sites.util.SitesUtil;
102    
103    import java.io.File;
104    import java.io.IOException;
105    import java.io.InputStream;
106    
107    import java.util.ArrayList;
108    import java.util.Date;
109    import java.util.HashSet;
110    import java.util.List;
111    import java.util.Locale;
112    import java.util.Map;
113    import java.util.Set;
114    
115    import org.apache.commons.lang.time.StopWatch;
116    
117    /**
118     * @author Brian Wing Shun Chan
119     * @author Joel Kozikowski
120     * @author Charles May
121     * @author Raymond Augé
122     * @author Jorge Ferrer
123     * @author Bruno Farache
124     * @author Wesley Gong
125     * @author Zsigmond Rab
126     * @author Douglas Wong
127     * @author Julio Camarero
128     * @author Zsolt Berentey
129     */
130    public class LayoutImporter {
131    
132            public void importLayouts(
133                            long userId, long groupId, boolean privateLayout,
134                            Map<String, String[]> parameterMap, File file)
135                    throws Exception {
136    
137                    try {
138                            ImportExportThreadLocal.setLayoutImportInProcess(true);
139    
140                            doImportLayouts(userId, groupId, privateLayout, parameterMap, file);
141                    }
142                    finally {
143                            ImportExportThreadLocal.setLayoutImportInProcess(false);
144    
145                            CacheUtil.clearCache();
146                            JournalContentUtil.clearCache();
147                            PermissionCacheUtil.clearCache();
148                    }
149            }
150    
151            protected String[] appendPortletIds(
152                    String[] portletIds, String[] newPortletIds, String portletsMergeMode) {
153    
154                    for (String portletId : newPortletIds) {
155                            if (ArrayUtil.contains(portletIds, portletId)) {
156                                    continue;
157                            }
158    
159                            if (portletsMergeMode.equals(
160                                            PortletDataHandlerKeys.PORTLETS_MERGE_MODE_ADD_TO_BOTTOM)) {
161    
162                                    portletIds = ArrayUtil.append(portletIds, portletId);
163                            }
164                            else {
165                                    portletIds = ArrayUtil.append(
166                                            new String[] {portletId}, portletIds);
167                            }
168                    }
169    
170                    return portletIds;
171            }
172    
173            protected void deleteMissingLayouts(
174                            long groupId, boolean privateLayout, Set<Long> newLayoutIds,
175                            List<Layout> previousLayouts, ServiceContext serviceContext)
176                    throws Exception {
177    
178                    // Layouts
179    
180                    if (_log.isDebugEnabled()) {
181                            if (newLayoutIds.size() > 0) {
182                                    _log.debug("Delete missing layouts");
183                            }
184                    }
185    
186                    for (Layout layout : previousLayouts) {
187                            if (!newLayoutIds.contains(layout.getLayoutId())) {
188                                    try {
189                                            LayoutLocalServiceUtil.deleteLayout(
190                                                    layout, false, serviceContext);
191                                    }
192                                    catch (NoSuchLayoutException nsle) {
193                                    }
194                            }
195                    }
196    
197                    // Layout set
198    
199                    LayoutSetLocalServiceUtil.updatePageCount(groupId, privateLayout);
200            }
201    
202            protected void doImportLayouts(
203                            long userId, long groupId, boolean privateLayout,
204                            Map<String, String[]> parameterMap, File file)
205                    throws Exception {
206    
207                    boolean deleteMissingLayouts = MapUtil.getBoolean(
208                            parameterMap, PortletDataHandlerKeys.DELETE_MISSING_LAYOUTS,
209                            Boolean.TRUE.booleanValue());
210                    boolean deletePortletData = MapUtil.getBoolean(
211                            parameterMap, PortletDataHandlerKeys.DELETE_PORTLET_DATA);
212                    boolean importCategories = MapUtil.getBoolean(
213                            parameterMap, PortletDataHandlerKeys.CATEGORIES);
214                    boolean importPermissions = MapUtil.getBoolean(
215                            parameterMap, PortletDataHandlerKeys.PERMISSIONS);
216                    boolean importPublicLayoutPermissions = MapUtil.getBoolean(
217                            parameterMap, PortletDataHandlerKeys.PUBLIC_LAYOUT_PERMISSIONS);
218                    boolean importUserPermissions = MapUtil.getBoolean(
219                            parameterMap, PortletDataHandlerKeys.USER_PERMISSIONS);
220                    boolean importPortletData = MapUtil.getBoolean(
221                            parameterMap, PortletDataHandlerKeys.PORTLET_DATA);
222                    boolean importPortletSetup = MapUtil.getBoolean(
223                            parameterMap, PortletDataHandlerKeys.PORTLET_SETUP);
224                    boolean importPortletArchivedSetups = MapUtil.getBoolean(
225                            parameterMap, PortletDataHandlerKeys.PORTLET_ARCHIVED_SETUPS);
226                    boolean importPortletUserPreferences = MapUtil.getBoolean(
227                            parameterMap, PortletDataHandlerKeys.PORTLET_USER_PREFERENCES);
228                    boolean importTheme = MapUtil.getBoolean(
229                            parameterMap, PortletDataHandlerKeys.THEME);
230                    boolean importThemeSettings = MapUtil.getBoolean(
231                            parameterMap, PortletDataHandlerKeys.THEME_REFERENCE);
232                    boolean importLogo = MapUtil.getBoolean(
233                            parameterMap, PortletDataHandlerKeys.LOGO);
234                    boolean importLayoutSetSettings = MapUtil.getBoolean(
235                            parameterMap, PortletDataHandlerKeys.LAYOUT_SET_SETTINGS);
236    
237                    boolean layoutSetPrototypeLinkEnabled = MapUtil.getBoolean(
238                            parameterMap,
239                            PortletDataHandlerKeys.LAYOUT_SET_PROTOTYPE_LINK_ENABLED, true);
240    
241                    Group group = GroupLocalServiceUtil.getGroup(groupId);
242    
243                    if (group.isLayoutSetPrototype()) {
244                            layoutSetPrototypeLinkEnabled = false;
245                    }
246    
247                    boolean publishToRemote = MapUtil.getBoolean(
248                            parameterMap, PortletDataHandlerKeys.PUBLISH_TO_REMOTE);
249                    String layoutsImportMode = MapUtil.getString(
250                            parameterMap, PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE,
251                            PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE_MERGE_BY_LAYOUT_UUID);
252                    String portletsMergeMode = MapUtil.getString(
253                            parameterMap, PortletDataHandlerKeys.PORTLETS_MERGE_MODE,
254                            PortletDataHandlerKeys.PORTLETS_MERGE_MODE_REPLACE);
255                    String userIdStrategy = MapUtil.getString(
256                            parameterMap, PortletDataHandlerKeys.USER_ID_STRATEGY);
257    
258                    if (_log.isDebugEnabled()) {
259                            _log.debug("Delete portlet data " + deletePortletData);
260                            _log.debug("Import categories " + importCategories);
261                            _log.debug("Import permissions " + importPermissions);
262                            _log.debug("Import user permissions " + importUserPermissions);
263                            _log.debug("Import portlet data " + importPortletData);
264                            _log.debug("Import portlet setup " + importPortletSetup);
265                            _log.debug(
266                                    "Import portlet archived setups " +
267                                            importPortletArchivedSetups);
268                            _log.debug(
269                                    "Import portlet user preferences " +
270                                            importPortletUserPreferences);
271                            _log.debug("Import theme " + importTheme);
272                    }
273    
274                    StopWatch stopWatch = null;
275    
276                    if (_log.isInfoEnabled()) {
277                            stopWatch = new StopWatch();
278    
279                            stopWatch.start();
280                    }
281    
282                    LayoutCache layoutCache = new LayoutCache();
283    
284                    LayoutSet layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
285                            groupId, privateLayout);
286    
287                    long companyId = layoutSet.getCompanyId();
288    
289                    User user = UserUtil.findByPrimaryKey(userId);
290    
291                    UserIdStrategy strategy = _portletImporter.getUserIdStrategy(
292                            user, userIdStrategy);
293    
294                    ZipReader zipReader = ZipReaderFactoryUtil.getZipReader(file);
295    
296                    PortletDataContext portletDataContext = new PortletDataContextImpl(
297                            companyId, groupId, parameterMap, new HashSet<String>(), strategy,
298                            zipReader);
299    
300                    portletDataContext.setPortetDataContextListener(
301                            new PortletDataContextListenerImpl(portletDataContext));
302    
303                    portletDataContext.setPrivateLayout(privateLayout);
304    
305                    // Zip
306    
307                    Element rootElement = null;
308                    InputStream themeZip = null;
309    
310                    // Manifest
311    
312                    String xml = portletDataContext.getZipEntryAsString("/manifest.xml");
313    
314                    if (xml == null) {
315                            throw new LARFileException("manifest.xml not found in the LAR");
316                    }
317    
318                    try {
319                            Document document = SAXReaderUtil.read(xml);
320    
321                            rootElement = document.getRootElement();
322                    }
323                    catch (Exception e) {
324                            throw new LARFileException(e);
325                    }
326    
327                    // Build compatibility
328    
329                    Element headerElement = rootElement.element("header");
330    
331                    int buildNumber = ReleaseInfo.getBuildNumber();
332    
333                    int importBuildNumber = GetterUtil.getInteger(
334                            headerElement.attributeValue("build-number"));
335    
336                    if (buildNumber != importBuildNumber) {
337                            throw new LayoutImportException(
338                                    "LAR build number " + importBuildNumber + " does not match " +
339                                            "portal build number " + buildNumber);
340                    }
341    
342                    // Type compatibility
343    
344                    String larType = headerElement.attributeValue("type");
345    
346                    if (!larType.equals("layout-set")) {
347                            throw new LARTypeException(
348                                    "Invalid type of LAR file (" + larType + ")");
349                    }
350    
351                    // Group id
352    
353                    long sourceGroupId = GetterUtil.getLong(
354                            headerElement.attributeValue("group-id"));
355    
356                    portletDataContext.setSourceGroupId(sourceGroupId);
357    
358                    // Layout set prototype
359    
360                    String layoutSetPrototypeUuid = headerElement.attributeValue(
361                            "layout-set-prototype-uuid");
362    
363                    ServiceContext serviceContext =
364                            ServiceContextThreadLocal.getServiceContext();
365    
366                    if (Validator.isNotNull(layoutSetPrototypeUuid)) {
367                            if (layoutSetPrototypeLinkEnabled) {
368                                    if (publishToRemote) {
369                                            importLayoutSetPrototype(
370                                                    portletDataContext, user, layoutSetPrototypeUuid,
371                                                    serviceContext);
372                                    }
373                            }
374    
375                            layoutSet.setLayoutSetPrototypeUuid(layoutSetPrototypeUuid);
376                            layoutSet.setLayoutSetPrototypeLinkEnabled(
377                                    layoutSetPrototypeLinkEnabled);
378    
379                            LayoutSetLocalServiceUtil.updateLayoutSet(layoutSet);
380                    }
381    
382                    // Look and feel
383    
384                    if (importTheme) {
385                            themeZip = portletDataContext.getZipEntryAsInputStream("theme.zip");
386                    }
387    
388                    // Look and feel
389    
390                    String themeId = layoutSet.getThemeId();
391                    String colorSchemeId = layoutSet.getColorSchemeId();
392    
393                    if (importThemeSettings) {
394                            Attribute themeIdAttribute = headerElement.attribute("theme-id");
395    
396                            if (themeIdAttribute != null) {
397                                    themeId = themeIdAttribute.getValue();
398                            }
399    
400                            Attribute colorSchemeIdAttribute = headerElement.attribute(
401                                    "color-scheme-id");
402    
403                            if (colorSchemeIdAttribute != null) {
404                                    colorSchemeId = colorSchemeIdAttribute.getValue();
405                            }
406                    }
407    
408                    if (importLogo) {
409                            String logoPath = headerElement.attributeValue("logo-path");
410    
411                            byte[] iconBytes = portletDataContext.getZipEntryAsByteArray(
412                                    logoPath);
413    
414                            if ((iconBytes != null) && (iconBytes.length > 0)) {
415                                    File logo = FileUtil.createTempFile(iconBytes);
416    
417                                    LayoutSetLocalServiceUtil.updateLogo(
418                                            groupId, privateLayout, true, logo);
419                            }
420                            else {
421                                    LayoutSetLocalServiceUtil.updateLogo(
422                                            groupId, privateLayout, false, (File) null);
423                            }
424                    }
425    
426                    if (importLayoutSetSettings) {
427                            String settings = GetterUtil.getString(
428                                    headerElement.elementText("settings"));
429    
430                            LayoutSetLocalServiceUtil.updateSettings(
431                                    groupId, privateLayout, settings);
432                    }
433    
434                    String css = GetterUtil.getString(headerElement.elementText("css"));
435    
436                    if (themeZip != null) {
437                            String importThemeId = importTheme(layoutSet, themeZip);
438    
439                            if (importThemeId != null) {
440                                    themeId = importThemeId;
441                                    colorSchemeId =
442                                            ColorSchemeImpl.getDefaultRegularColorSchemeId();
443                            }
444    
445                            if (_log.isDebugEnabled()) {
446                                    _log.debug(
447                                            "Importing theme takes " + stopWatch.getTime() + " ms");
448                            }
449                    }
450    
451                    boolean wapTheme = false;
452    
453                    LayoutSetLocalServiceUtil.updateLookAndFeel(
454                            groupId, privateLayout, themeId, colorSchemeId, css, wapTheme);
455    
456                    // Read asset categories, asset tags, comments, locks, permissions, and
457                    // ratings entries to make them available to the data handlers through
458                    // the context
459    
460                    if (importPermissions) {
461                            _permissionImporter.readPortletDataPermissions(portletDataContext);
462                    }
463    
464                    if (importCategories) {
465                            _portletImporter.readAssetCategories(portletDataContext);
466                    }
467    
468                    _portletImporter.readAssetTags(portletDataContext);
469                    _portletImporter.readComments(portletDataContext);
470                    _portletImporter.readExpandoTables(portletDataContext);
471                    _portletImporter.readLocks(portletDataContext);
472                    _portletImporter.readRatingsEntries(portletDataContext);
473    
474                    // Layouts
475    
476                    List<Layout> previousLayouts = LayoutUtil.findByG_P(
477                            groupId, privateLayout);
478    
479                    // Remove layouts that were deleted from the layout set prototype
480    
481                    if (Validator.isNotNull(layoutSetPrototypeUuid) &&
482                            layoutSetPrototypeLinkEnabled) {
483    
484                            LayoutSetPrototype layoutSetPrototype =
485                                    LayoutSetPrototypeLocalServiceUtil.getLayoutSetPrototypeByUuid(
486                                            layoutSetPrototypeUuid);
487    
488                            Group layoutSetPrototypeGroup = layoutSetPrototype.getGroup();
489    
490                            for (Layout layout : previousLayouts) {
491                                    String sourcePrototypeLayoutUuid =
492                                            layout.getSourcePrototypeLayoutUuid();
493    
494                                    if (Validator.isNull(layout.getSourcePrototypeLayoutUuid())) {
495                                            continue;
496                                    }
497    
498                                    Layout sourcePrototypeLayout = LayoutUtil.fetchByUUID_G(
499                                            sourcePrototypeLayoutUuid,
500                                            layoutSetPrototypeGroup.getGroupId());
501    
502                                    if (sourcePrototypeLayout == null) {
503                                            LayoutLocalServiceUtil.deleteLayout(
504                                                    layout, false, serviceContext);
505                                    }
506                            }
507                    }
508    
509                    List<Layout> newLayouts = new ArrayList<Layout>();
510    
511                    Set<Long> newLayoutIds = new HashSet<Long>();
512    
513                    Map<Long, Layout> newLayoutsMap =
514                            (Map<Long, Layout>)portletDataContext.getNewPrimaryKeysMap(
515                                    Layout.class);
516    
517                    Element layoutsElement = rootElement.element("layouts");
518    
519                    List<Element> layoutElements = layoutsElement.elements("layout");
520    
521                    if (_log.isDebugEnabled()) {
522                            if (layoutElements.size() > 0) {
523                                    _log.debug("Importing layouts");
524                            }
525                    }
526    
527                    for (Element layoutElement : layoutElements) {
528                            importLayout(
529                                    portletDataContext, user, layoutCache, previousLayouts,
530                                    newLayouts, newLayoutsMap, newLayoutIds, portletsMergeMode,
531                                    themeId, colorSchemeId, layoutsImportMode, privateLayout,
532                                    importPermissions, importPublicLayoutPermissions,
533                                    importUserPermissions, importThemeSettings, rootElement,
534                                    layoutElement);
535                    }
536    
537                    Element portletsElement = rootElement.element("portlets");
538    
539                    List<Element> portletElements = portletsElement.elements("portlet");
540    
541                    // Delete portlet data
542    
543                    if (deletePortletData) {
544                            if (_log.isDebugEnabled()) {
545                                    if (portletElements.size() > 0) {
546                                            _log.debug("Deleting portlet data");
547                                    }
548                            }
549    
550                            for (Element portletElement : portletElements) {
551                                    String portletId = portletElement.attributeValue("portlet-id");
552                                    long layoutId = GetterUtil.getLong(
553                                            portletElement.attributeValue("layout-id"));
554                                    long plid = newLayoutsMap.get(layoutId).getPlid();
555    
556                                    portletDataContext.setPlid(plid);
557    
558                                    _portletImporter.deletePortletData(
559                                            portletDataContext, portletId, plid);
560                            }
561                    }
562    
563                    // Import portlets
564    
565                    if (_log.isDebugEnabled()) {
566                            if (portletElements.size() > 0) {
567                                    _log.debug("Importing portlets");
568                            }
569                    }
570    
571                    for (Element portletElement : portletElements) {
572                            String portletPath = portletElement.attributeValue("path");
573                            String portletId = portletElement.attributeValue("portlet-id");
574                            long layoutId = GetterUtil.getLong(
575                                    portletElement.attributeValue("layout-id"));
576                            long plid = newLayoutsMap.get(layoutId).getPlid();
577                            long oldPlid = GetterUtil.getLong(
578                                    portletElement.attributeValue("old-plid"));
579    
580                            Portlet portlet = PortletLocalServiceUtil.getPortletById(
581                                    portletDataContext.getCompanyId(), portletId);
582    
583                            if (!portlet.isActive() || portlet.isUndeployedPortlet()) {
584                                    continue;
585                            }
586    
587                            Layout layout = null;
588    
589                            try {
590                                    layout = LayoutUtil.findByPrimaryKey(plid);
591                            }
592                            catch (NoSuchLayoutException nsle) {
593                                    continue;
594                            }
595    
596                            portletDataContext.setPlid(plid);
597                            portletDataContext.setOldPlid(oldPlid);
598    
599                            Document portletDocument = SAXReaderUtil.read(
600                                    portletDataContext.getZipEntryAsString(portletPath));
601    
602                            portletElement = portletDocument.getRootElement();
603    
604                            // The order of the import is important. You must always import
605                            // the portlet preferences first, then the portlet data, then
606                            // the portlet permissions. The import of the portlet data
607                            // assumes that portlet preferences already exist.
608    
609                            _portletImporter.setPortletScope(
610                                    portletDataContext, portletElement);
611    
612                            try {
613    
614                                    // Portlet preferences
615    
616                                    _portletImporter.importPortletPreferences(
617                                            portletDataContext, layoutSet.getCompanyId(),
618                                            layout.getGroupId(), layout, null, portletElement,
619                                            importPortletSetup, importPortletArchivedSetups,
620                                            importPortletUserPreferences, false);
621    
622                                    // Portlet data
623    
624                                    Element portletDataElement = portletElement.element(
625                                            "portlet-data");
626    
627                                    if (importPortletData && (portletDataElement != null)) {
628                                            _portletImporter.importPortletData(
629                                                    portletDataContext, portletId, plid,
630                                                    portletDataElement);
631                                    }
632                            }
633                            finally {
634                                    _portletImporter.resetPortletScope(
635                                            portletDataContext, layout.getGroupId());
636                            }
637    
638                            // Portlet permissions
639    
640                            if (importPermissions) {
641                                    _permissionImporter.importPortletPermissions(
642                                            layoutCache, companyId, groupId, userId, layout,
643                                            portletElement, portletId, importUserPermissions);
644                            }
645    
646                            // Archived setups
647    
648                            _portletImporter.importPortletPreferences(
649                                    portletDataContext, layoutSet.getCompanyId(), groupId, null,
650                                    null, portletElement, importPortletSetup,
651                                    importPortletArchivedSetups, importPortletUserPreferences,
652                                    false);
653                    }
654    
655                    if (importPermissions) {
656                            if ((userId > 0) &&
657                                    ((PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 5) ||
658                                     (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 6))) {
659    
660                                    Indexer indexer = IndexerRegistryUtil.getIndexer(User.class);
661    
662                                    indexer.reindex(userId);
663                            }
664                    }
665    
666                    // Asset links
667    
668                    _portletImporter.readAssetLinks(portletDataContext);
669    
670                    // Delete missing layouts
671    
672                    if (deleteMissingLayouts) {
673                            deleteMissingLayouts(
674                                    groupId, privateLayout, newLayoutIds, previousLayouts,
675                                    serviceContext);
676                    }
677    
678                    // Page count
679    
680                    LayoutSetLocalServiceUtil.updatePageCount(groupId, privateLayout);
681    
682                    if (_log.isInfoEnabled()) {
683                            _log.info("Importing layouts takes " + stopWatch.getTime() + " ms");
684                    }
685    
686                    // Site
687    
688                    GroupLocalServiceUtil.updateSite(groupId, true);
689    
690                    // Web content layout type
691    
692                    for (Layout layout : newLayouts) {
693                            UnicodeProperties typeSettingsProperties =
694                                    layout.getTypeSettingsProperties();
695    
696                            String articleId = typeSettingsProperties.getProperty("article-id");
697    
698                            if (Validator.isNotNull(articleId)) {
699                                    Map<String, String> articleIds =
700                                            (Map<String, String>)portletDataContext.
701                                                    getNewPrimaryKeysMap(
702                                                            JournalArticle.class + ".articleId");
703    
704                                    typeSettingsProperties.setProperty(
705                                            "article-id",
706                                            MapUtil.getString(articleIds, articleId, articleId));
707    
708                                    LayoutUtil.update(layout, false);
709                            }
710                    }
711    
712                    zipReader.close();
713            }
714    
715            protected void fixTypeSettings(Layout layout) throws Exception {
716                    if (!layout.isTypeURL()) {
717                            return;
718                    }
719    
720                    UnicodeProperties typeSettings = layout.getTypeSettingsProperties();
721    
722                    String url = GetterUtil.getString(typeSettings.getProperty("url"));
723    
724                    String friendlyURLPrivateGroupPath =
725                            PropsValues.LAYOUT_FRIENDLY_URL_PRIVATE_GROUP_SERVLET_MAPPING;
726                    String friendlyURLPrivateUserPath =
727                            PropsValues.LAYOUT_FRIENDLY_URL_PRIVATE_USER_SERVLET_MAPPING;
728                    String friendlyURLPublicPath =
729                            PropsValues.LAYOUT_FRIENDLY_URL_PUBLIC_SERVLET_MAPPING;
730    
731                    if (!url.startsWith(friendlyURLPrivateGroupPath) &&
732                            !url.startsWith(friendlyURLPrivateUserPath) &&
733                            !url.startsWith(friendlyURLPublicPath)) {
734    
735                            return;
736                    }
737    
738                    int x = url.indexOf(CharPool.SLASH, 1);
739    
740                    if (x == -1) {
741                            return;
742                    }
743    
744                    int y = url.indexOf(CharPool.SLASH, x + 1);
745    
746                    if (y == -1) {
747                            return;
748                    }
749    
750                    String friendlyURL = url.substring(x, y);
751    
752                    if (!friendlyURL.equals(LayoutExporter.SAME_GROUP_FRIENDLY_URL)) {
753                            return;
754                    }
755    
756                    Group group = layout.getGroup();
757    
758                    typeSettings.setProperty(
759                            "url",
760                            url.substring(0, x) + group.getFriendlyURL() + url.substring(y));
761            }
762    
763            protected String getLayoutSetPrototype(
764                    PortletDataContext portletDataContext, String layoutSetPrototypeUuid) {
765    
766                    StringBundler sb = new StringBundler(3);
767    
768                    sb.append(portletDataContext.getSourceRootPath());
769                    sb.append("/layout-set-prototype/");
770                    sb.append(layoutSetPrototypeUuid);
771    
772                    return sb.toString();
773            }
774    
775            protected void importJournalArticle(
776                            PortletDataContext portletDataContext, Layout layout,
777                            Element layoutElement)
778                    throws Exception {
779    
780                    UnicodeProperties typeSettingsProperties =
781                            layout.getTypeSettingsProperties();
782    
783                    String articleId = typeSettingsProperties.getProperty(
784                            "article-id", StringPool.BLANK);
785    
786                    if (Validator.isNull(articleId)) {
787                            return;
788                    }
789    
790                    JournalPortletDataHandlerImpl.importReferencedData(
791                            portletDataContext, layoutElement);
792    
793                    Element structureElement = layoutElement.element("structure");
794    
795                    if (structureElement != null) {
796                            JournalPortletDataHandlerImpl.importStructure(
797                                    portletDataContext, structureElement);
798                    }
799    
800                    Element templateElement = layoutElement.element("template");
801    
802                    if (templateElement != null) {
803                            JournalPortletDataHandlerImpl.importTemplate(
804                                    portletDataContext, templateElement);
805                    }
806    
807                    Element articleElement = layoutElement.element("article");
808    
809                    if (articleElement != null) {
810                            JournalPortletDataHandlerImpl.importArticle(
811                                    portletDataContext, articleElement);
812                    }
813    
814                    Map<String, String> articleIds =
815                            (Map<String, String>)portletDataContext.getNewPrimaryKeysMap(
816                                    JournalArticle.class + ".articleId");
817    
818                    articleId = MapUtil.getString(articleIds, articleId, articleId);
819    
820                    typeSettingsProperties.setProperty("article-id", articleId);
821    
822                    JournalContentSearchLocalServiceUtil.updateContentSearch(
823                            portletDataContext.getScopeGroupId(), layout.isPrivateLayout(),
824                            layout.getLayoutId(), StringPool.BLANK, articleId, true);
825            }
826    
827            protected void importLayout(
828                            PortletDataContext portletDataContext, User user,
829                            LayoutCache layoutCache, List<Layout> previousLayouts,
830                            List<Layout> newLayouts, Map<Long, Layout> newLayoutsMap,
831                            Set<Long> newLayoutIds, String portletsMergeMode, String themeId,
832                            String colorSchemeId, String layoutsImportMode,
833                            boolean privateLayout, boolean importPermissions,
834                            boolean importPublicLayoutPermissions,
835                            boolean importUserPermissions, boolean importThemeSettings,
836                            Element rootElement, Element layoutElement)
837                    throws Exception {
838    
839                    long groupId = portletDataContext.getGroupId();
840    
841                    String layoutUuid = GetterUtil.getString(
842                            layoutElement.attributeValue("layout-uuid"));
843    
844                    long layoutId = GetterUtil.getInteger(
845                            layoutElement.attributeValue("layout-id"));
846    
847                    long oldLayoutId = layoutId;
848    
849                    boolean deleteLayout = GetterUtil.getBoolean(
850                            layoutElement.attributeValue("delete"));
851    
852                    if (deleteLayout) {
853                            Layout layout = LayoutLocalServiceUtil.fetchLayoutByUuidAndGroupId(
854                                    layoutUuid, groupId);
855    
856                            if (layout != null) {
857                                    newLayoutsMap.put(oldLayoutId, layout);
858    
859                                    ServiceContext serviceContext =
860                                            ServiceContextThreadLocal.getServiceContext();
861    
862                                    LayoutLocalServiceUtil.deleteLayout(
863                                            layout, false, serviceContext);
864                            }
865    
866                            return;
867                    }
868    
869                    String path = layoutElement.attributeValue("path");
870    
871                    if (!portletDataContext.isPathNotProcessed(path)) {
872                            return;
873                    }
874    
875                    Layout layout = (Layout)portletDataContext.getZipEntryAsObject(path);
876    
877                    Layout existingLayout = null;
878                    Layout importedLayout = null;
879    
880                    String friendlyURL = layout.getFriendlyURL();
881    
882                    if (layoutsImportMode.equals(
883                                    PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE_ADD_AS_NEW)) {
884    
885                            layoutId = LayoutLocalServiceUtil.getNextLayoutId(
886                                    groupId, privateLayout);
887                            friendlyURL = StringPool.SLASH + layoutId;
888                    }
889                    else if (layoutsImportMode.equals(
890                                            PortletDataHandlerKeys.
891                                                    LAYOUTS_IMPORT_MODE_MERGE_BY_LAYOUT_NAME)) {
892    
893                            Locale locale = LocaleUtil.getDefault();
894    
895                            String localizedName = layout.getName(locale);
896    
897                            for (Layout curLayout : previousLayouts) {
898                                    if (localizedName.equals(curLayout.getName(locale)) ||
899                                            friendlyURL.equals(curLayout.getFriendlyURL())) {
900    
901                                            existingLayout = curLayout;
902    
903                                            break;
904                                    }
905                            }
906    
907                            if (existingLayout == null) {
908                                    layoutId = LayoutLocalServiceUtil.getNextLayoutId(
909                                            groupId, privateLayout);
910                            }
911                    }
912                    else if (layoutsImportMode.equals(
913                                            PortletDataHandlerKeys.
914                                                    LAYOUTS_IMPORT_MODE_CREATED_FROM_PROTOTYPE)) {
915    
916                            existingLayout = LayoutUtil.fetchByG_P_SPLU(
917                                    groupId, privateLayout, layout.getUuid());
918    
919                            if (SitesUtil.isLayoutModifiedSinceLastMerge(existingLayout)) {
920                                    newLayoutsMap.put(oldLayoutId, existingLayout);
921    
922                                    return;
923                            }
924                    }
925                    else {
926    
927                            // The default behaviour of import mode is
928                            // PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE_MERGE_BY_LAYOUT_UUID
929    
930                            existingLayout = LayoutUtil.fetchByUUID_G(
931                                    layout.getUuid(), groupId);
932    
933                            if (existingLayout == null) {
934                                    existingLayout = LayoutUtil.fetchByG_P_F(
935                                            groupId, privateLayout, friendlyURL);
936                            }
937    
938                            if (existingLayout == null) {
939                                    layoutId = LayoutLocalServiceUtil.getNextLayoutId(
940                                            groupId, privateLayout);
941                            }
942                    }
943    
944                    if (_log.isDebugEnabled()) {
945                            if (existingLayout == null) {
946                                    _log.debug(
947                                            "Layout with {groupId=" + groupId + ",privateLayout=" +
948                                                    privateLayout + ",layoutId=" + layoutId +
949                                                            "} does not exist");
950                            }
951                            else {
952                                    _log.debug(
953                                            "Layout with {groupId=" + groupId + ",privateLayout=" +
954                                                    privateLayout + ",layoutId=" + layoutId + "} exists");
955                            }
956                    }
957    
958                    if (existingLayout == null) {
959                            long plid = CounterLocalServiceUtil.increment();
960    
961                            importedLayout = LayoutUtil.create(plid);
962    
963                            if (layoutsImportMode.equals(
964                                            PortletDataHandlerKeys.
965                                                    LAYOUTS_IMPORT_MODE_CREATED_FROM_PROTOTYPE)) {
966    
967                                    importedLayout.setSourcePrototypeLayoutUuid(layout.getUuid());
968    
969                                    layoutId = LayoutLocalServiceUtil.getNextLayoutId(
970                                            groupId, privateLayout);
971                            }
972                            else {
973                                    importedLayout.setUuid(layout.getUuid());
974                                    importedLayout.setLayoutPrototypeUuid(
975                                            layout.getLayoutPrototypeUuid());
976                                    importedLayout.setLayoutPrototypeLinkEnabled(
977                                            layout.isLayoutPrototypeLinkEnabled());
978                                    importedLayout.setSourcePrototypeLayoutUuid(
979                                            layout.getSourcePrototypeLayoutUuid());
980                            }
981    
982                            importedLayout.setGroupId(groupId);
983                            importedLayout.setPrivateLayout(privateLayout);
984                            importedLayout.setLayoutId(layoutId);
985    
986                            // Resources
987    
988                            boolean addGroupPermissions = true;
989    
990                            Group group = importedLayout.getGroup();
991    
992                            if (privateLayout && group.isUser()) {
993                                    addGroupPermissions = false;
994                            }
995    
996                            boolean addGuestPermissions = false;
997    
998                            if (!privateLayout || layout.isTypeControlPanel()) {
999                                    addGuestPermissions = true;
1000                            }
1001    
1002                            ResourceLocalServiceUtil.addResources(
1003                                    user.getCompanyId(), groupId, user.getUserId(),
1004                                    Layout.class.getName(), importedLayout.getPlid(), false,
1005                                    addGroupPermissions, addGuestPermissions);
1006    
1007                            LayoutSet layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
1008                                    groupId, privateLayout);
1009    
1010                            importedLayout.setLayoutSet(layoutSet);
1011                    }
1012                    else {
1013                            importedLayout = existingLayout;
1014                    }
1015    
1016                    newLayoutsMap.put(oldLayoutId, importedLayout);
1017    
1018                    long parentLayoutId = layout.getParentLayoutId();
1019    
1020                    Node parentLayoutNode = rootElement.selectSingleNode(
1021                            "./layouts/layout[@layout-id='" + parentLayoutId + "']");
1022    
1023                    String parentLayoutUuid = GetterUtil.getString(
1024                            layoutElement.attributeValue("parent-layout-uuid"));
1025    
1026                    if ((parentLayoutId != LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) &&
1027                            (parentLayoutNode != null)) {
1028    
1029                            importLayout(
1030                                    portletDataContext, user, layoutCache, previousLayouts,
1031                                    newLayouts, newLayoutsMap, newLayoutIds, portletsMergeMode,
1032                                    themeId, colorSchemeId, layoutsImportMode, privateLayout,
1033                                    importPermissions, importPublicLayoutPermissions,
1034                                    importUserPermissions, importThemeSettings, rootElement,
1035                                    (Element)parentLayoutNode);
1036    
1037                            Layout parentLayout = newLayoutsMap.get(parentLayoutId);
1038    
1039                            parentLayoutId = parentLayout.getLayoutId();
1040                    }
1041                    else if (Validator.isNotNull(parentLayoutUuid)) {
1042                            Layout parentLayout =
1043                                    LayoutLocalServiceUtil.getLayoutByUuidAndGroupId(
1044                                            parentLayoutUuid, groupId);
1045    
1046                            parentLayoutId = parentLayout.getLayoutId();
1047                    }
1048    
1049                    if (_log.isDebugEnabled()) {
1050                            _log.debug(
1051                                    "Importing layout with layout id " + layoutId +
1052                                            " and parent layout id " + parentLayoutId);
1053                    }
1054    
1055                    importedLayout.setCompanyId(user.getCompanyId());
1056                    importedLayout.setParentLayoutId(parentLayoutId);
1057                    importedLayout.setName(layout.getName());
1058                    importedLayout.setTitle(layout.getTitle());
1059                    importedLayout.setDescription(layout.getDescription());
1060                    importedLayout.setKeywords(layout.getKeywords());
1061                    importedLayout.setRobots(layout.getRobots());
1062                    importedLayout.setType(layout.getType());
1063    
1064                    if (layout.isTypeArticle()) {
1065                            importJournalArticle(portletDataContext, layout, layoutElement);
1066    
1067                            importedLayout.setTypeSettings(layout.getTypeSettings());
1068                    }
1069                    else if (layout.isTypePortlet() &&
1070                                     Validator.isNotNull(layout.getTypeSettings()) &&
1071                                     !portletsMergeMode.equals(
1072                                             PortletDataHandlerKeys.PORTLETS_MERGE_MODE_REPLACE)) {
1073    
1074                            mergePortlets(
1075                                    importedLayout, layout.getTypeSettings(), portletsMergeMode);
1076                    }
1077                    else if (layout.isTypeLinkToLayout()) {
1078                            UnicodeProperties typeSettingsProperties =
1079                                    layout.getTypeSettingsProperties();
1080    
1081                            long linkToLayoutId = GetterUtil.getLong(
1082                                    typeSettingsProperties.getProperty(
1083                                            "linkToLayoutId", StringPool.BLANK));
1084    
1085                            if (linkToLayoutId > 0) {
1086                                    Node linkedLayoutNode = rootElement.selectSingleNode(
1087                                            "./layouts/layout[@layout-id='" + linkToLayoutId + "']");
1088    
1089                                    if (linkedLayoutNode != null) {
1090                                            importLayout(
1091                                                    portletDataContext, user, layoutCache, previousLayouts,
1092                                                    newLayouts, newLayoutsMap, newLayoutIds,
1093                                                    portletsMergeMode, themeId, colorSchemeId,
1094                                                    layoutsImportMode, privateLayout, importPermissions,
1095                                                    importPublicLayoutPermissions, importUserPermissions,
1096                                                    importThemeSettings, rootElement,
1097                                                    (Element)linkedLayoutNode);
1098    
1099                                            Layout linkedLayout = newLayoutsMap.get(linkToLayoutId);
1100    
1101                                            typeSettingsProperties.setProperty(
1102                                                    "privateLayout",
1103                                                    String.valueOf(linkedLayout.getPrivateLayout()));
1104                                            typeSettingsProperties.setProperty(
1105                                                    "linkToLayoutId",
1106                                                    String.valueOf(linkedLayout.getLayoutId()));
1107                                    }
1108                                    else {
1109                                            if (_log.isWarnEnabled()) {
1110                                                    StringBundler sb = new StringBundler();
1111    
1112                                                    sb.append("Unable to link layout with friendly URL ");
1113                                                    sb.append(layout.getFriendlyURL());
1114                                                    sb.append(" and layout id ");
1115                                                    sb.append(layout.getLayoutId());
1116                                                    sb.append(" to layout with layout id ");
1117                                                    sb.append(linkToLayoutId);
1118    
1119                                                    _log.warn(sb.toString());
1120                                            }
1121                                    }
1122                            }
1123    
1124                            importedLayout.setTypeSettings(layout.getTypeSettings());
1125                    }
1126                    else {
1127                            importedLayout.setTypeSettings(layout.getTypeSettings());
1128                    }
1129    
1130                    importedLayout.setHidden(layout.isHidden());
1131                    importedLayout.setFriendlyURL(friendlyURL);
1132    
1133                    if (importThemeSettings) {
1134                            importedLayout.setThemeId(layout.getThemeId());
1135                            importedLayout.setColorSchemeId(layout.getColorSchemeId());
1136                    }
1137                    else {
1138                            importedLayout.setThemeId(StringPool.BLANK);
1139                            importedLayout.setColorSchemeId(StringPool.BLANK);
1140                    }
1141    
1142                    importedLayout.setWapThemeId(layout.getWapThemeId());
1143                    importedLayout.setWapColorSchemeId(layout.getWapColorSchemeId());
1144                    importedLayout.setCss(layout.getCss());
1145                    importedLayout.setPriority(layout.getPriority());
1146                    importedLayout.setLayoutPrototypeUuid(layout.getLayoutPrototypeUuid());
1147                    importedLayout.setLayoutPrototypeLinkEnabled(
1148                            layout.isLayoutPrototypeLinkEnabled());
1149    
1150                    StagingUtil.updateLastImportSettings(
1151                            layoutElement, importedLayout, portletDataContext);
1152    
1153                    fixTypeSettings(importedLayout);
1154    
1155                    importedLayout.setIconImage(false);
1156    
1157                    if (layout.isIconImage()) {
1158                            String iconImagePath = layoutElement.elementText("icon-image-path");
1159    
1160                            byte[] iconBytes = portletDataContext.getZipEntryAsByteArray(
1161                                    iconImagePath);
1162    
1163                            if ((iconBytes != null) && (iconBytes.length > 0)) {
1164                                    importedLayout.setIconImage(true);
1165    
1166                                    if (importedLayout.getIconImageId() == 0) {
1167                                            long iconImageId = CounterLocalServiceUtil.increment();
1168    
1169                                            importedLayout.setIconImageId(iconImageId);
1170                                    }
1171    
1172                                    ImageLocalServiceUtil.updateImage(
1173                                            importedLayout.getIconImageId(), iconBytes);
1174                            }
1175                    }
1176                    else {
1177                            ImageLocalServiceUtil.deleteImage(importedLayout.getIconImageId());
1178                    }
1179    
1180                    ServiceContext serviceContext = portletDataContext.createServiceContext(
1181                            layoutElement, importedLayout, null);
1182    
1183                    importedLayout.setExpandoBridgeAttributes(serviceContext);
1184    
1185                    LayoutUtil.update(importedLayout, false);
1186    
1187                    portletDataContext.setPlid(importedLayout.getPlid());
1188                    portletDataContext.setOldPlid(layout.getPlid());
1189    
1190                    newLayoutIds.add(importedLayout.getLayoutId());
1191    
1192                    newLayouts.add(importedLayout);
1193    
1194                    // Layout permissions
1195    
1196                    if (importPermissions) {
1197                            _permissionImporter.importLayoutPermissions(
1198                                    layoutCache, portletDataContext.getCompanyId(), groupId,
1199                                    user.getUserId(), importedLayout, layoutElement, rootElement,
1200                                    importUserPermissions);
1201                    }
1202    
1203                    if (importPublicLayoutPermissions) {
1204                            String resourceName = Layout.class.getName();
1205                            String resourcePrimKey = String.valueOf(importedLayout.getPlid());
1206    
1207                            Role guestRole = RoleLocalServiceUtil.getRole(
1208                                    importedLayout.getCompanyId(), RoleConstants.GUEST);
1209    
1210                            if (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 5) {
1211                                    Resource resource = layoutCache.getResource(
1212                                            importedLayout.getCompanyId(), groupId, resourceName,
1213                                            ResourceConstants.SCOPE_INDIVIDUAL, resourcePrimKey, false);
1214    
1215                                    PermissionLocalServiceUtil.setRolePermissions(
1216                                            guestRole.getRoleId(), new String[] {ActionKeys.VIEW},
1217                                            resource.getResourceId());
1218                            }
1219                            else if (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 6) {
1220                                    ResourcePermissionLocalServiceUtil.setResourcePermissions(
1221                                            importedLayout.getCompanyId(), resourceName,
1222                                            ResourceConstants.SCOPE_INDIVIDUAL, resourcePrimKey,
1223                                            guestRole.getRoleId(), new String[] {ActionKeys.VIEW});
1224                            }
1225                            else {
1226                                    Resource resource = layoutCache.getResource(
1227                                            importedLayout.getCompanyId(), groupId, resourceName,
1228                                            ResourceConstants.SCOPE_INDIVIDUAL, resourcePrimKey, false);
1229    
1230                                    PermissionLocalServiceUtil.setGroupPermissions(
1231                                            groupId, new String[] {ActionKeys.VIEW},
1232                                            resource.getResourceId());
1233                            }
1234                    }
1235    
1236                    _portletImporter.importPortletData(
1237                            portletDataContext, PortletKeys.LAYOUT_CONFIGURATION, null,
1238                            layoutElement);
1239            }
1240    
1241            protected void importLayoutSetPrototype(
1242                            PortletDataContext portletDataContext, User user,
1243                            String layoutSetPrototypeUuid, ServiceContext serviceContext)
1244                    throws PortalException, SystemException {
1245    
1246                    String path = getLayoutSetPrototype(
1247                            portletDataContext, layoutSetPrototypeUuid);
1248    
1249                    LayoutSetPrototype layoutSetPrototype = null;
1250    
1251                    try {
1252                            layoutSetPrototype =
1253                                    LayoutSetPrototypeLocalServiceUtil.getLayoutSetPrototypeByUuid(
1254                                            layoutSetPrototypeUuid);
1255                    }
1256                    catch (NoSuchLayoutSetPrototypeException nslspe) {
1257                    }
1258    
1259                    if (layoutSetPrototype == null) {
1260                            layoutSetPrototype =
1261                                    (LayoutSetPrototype)portletDataContext.getZipEntryAsObject(
1262                                            path.concat(".xml"));
1263    
1264                            serviceContext.setUuid(layoutSetPrototypeUuid);
1265    
1266                            layoutSetPrototype =
1267                                    LayoutSetPrototypeLocalServiceUtil.addLayoutSetPrototype(
1268                                            user.getUserId(), user.getCompanyId(),
1269                                            layoutSetPrototype.getNameMap(),
1270                                            layoutSetPrototype.getDescription(),
1271                                            layoutSetPrototype.getActive(), true, serviceContext);
1272                    }
1273    
1274                    InputStream inputStream = portletDataContext.getZipEntryAsInputStream(
1275                            path.concat(".lar"));
1276    
1277                    SitesUtil.importLayoutSetPrototype(
1278                            layoutSetPrototype, inputStream, serviceContext);
1279            }
1280    
1281            protected String importTheme(LayoutSet layoutSet, InputStream themeZip)
1282                    throws Exception {
1283    
1284                    ThemeLoader themeLoader = ThemeLoaderFactory.getDefaultThemeLoader();
1285    
1286                    if (themeLoader == null) {
1287                            _log.error("No theme loaders are deployed");
1288    
1289                            return null;
1290                    }
1291    
1292                    ZipReader zipReader = ZipReaderFactoryUtil.getZipReader(themeZip);
1293    
1294                    String lookAndFeelXML = zipReader.getEntryAsString(
1295                            "liferay-look-and-feel.xml");
1296    
1297                    String themeId = String.valueOf(layoutSet.getGroupId());
1298    
1299                    if (layoutSet.isPrivateLayout()) {
1300                            themeId += "-private";
1301                    }
1302                    else {
1303                            themeId += "-public";
1304                    }
1305    
1306                    if (PropsValues.THEME_LOADER_NEW_THEME_ID_ON_IMPORT) {
1307                            Date now = new Date();
1308    
1309                            themeId += "-" + Time.getShortTimestamp(now);
1310                    }
1311    
1312                    String themeName = themeId;
1313    
1314                    lookAndFeelXML = StringUtil.replace(
1315                            lookAndFeelXML,
1316                            new String[] {
1317                                    "[$GROUP_ID$]", "[$THEME_ID$]", "[$THEME_NAME$]"
1318                            },
1319                            new String[] {
1320                                    String.valueOf(layoutSet.getGroupId()), themeId, themeName
1321                            }
1322                    );
1323    
1324                    FileUtil.deltree(
1325                            themeLoader.getFileStorage() + StringPool.SLASH + themeId);
1326    
1327                    List<String> zipEntries = zipReader.getEntries();
1328    
1329                    for (String zipEntry : zipEntries) {
1330                            String key = zipEntry;
1331    
1332                            if (key.equals("liferay-look-and-feel.xml")) {
1333                                    FileUtil.write(
1334                                            themeLoader.getFileStorage() + StringPool.SLASH + themeId +
1335                                                    StringPool.SLASH + key,
1336                                            lookAndFeelXML.getBytes());
1337                            }
1338                            else {
1339                                    InputStream is = zipReader.getEntryAsInputStream(zipEntry);
1340    
1341                                    FileUtil.write(
1342                                            themeLoader.getFileStorage() + StringPool.SLASH + themeId +
1343                                                    StringPool.SLASH + key,
1344                                            is);
1345                            }
1346                    }
1347    
1348                    themeLoader.loadThemes();
1349    
1350                    ClusterRequest clusterRequest = ClusterRequest.createMulticastRequest(
1351                            _loadThemesMethodHandler, true);
1352    
1353                    clusterRequest.setFireAndForget(true);
1354    
1355                    ClusterExecutorUtil.execute(clusterRequest);
1356    
1357                    themeId +=
1358                            PortletConstants.WAR_SEPARATOR +
1359                                    themeLoader.getServletContextName();
1360    
1361                    return PortalUtil.getJsSafePortletId(themeId);
1362            }
1363    
1364            protected void mergePortlets(
1365                    Layout layout, String newTypeSettings, String portletsMergeMode) {
1366    
1367                    try {
1368                            UnicodeProperties previousTypeSettingsProperties =
1369                                    layout.getTypeSettingsProperties();
1370    
1371                            LayoutTypePortlet previousLayoutType =
1372                                    (LayoutTypePortlet)layout.getLayoutType();
1373    
1374                            LayoutTemplate previousLayoutTemplate =
1375                                    previousLayoutType.getLayoutTemplate();
1376    
1377                            List<String> previousColumns = previousLayoutTemplate.getColumns();
1378    
1379                            UnicodeProperties newTypeSettingsProperties = new UnicodeProperties(
1380                                    true);
1381    
1382                            newTypeSettingsProperties.load(newTypeSettings);
1383    
1384                            String layoutTemplateId = newTypeSettingsProperties.getProperty(
1385                                    LayoutTypePortletConstants.LAYOUT_TEMPLATE_ID);
1386    
1387                            previousTypeSettingsProperties.setProperty(
1388                                    LayoutTypePortletConstants.LAYOUT_TEMPLATE_ID,
1389                                    layoutTemplateId);
1390    
1391                            LayoutTemplate newLayoutTemplate =
1392                                    LayoutTemplateLocalServiceUtil.getLayoutTemplate(
1393                                            layoutTemplateId, false, null);
1394    
1395                            String[] newPortletIds = new String[0];
1396    
1397                            for (String columnId : newLayoutTemplate.getColumns()) {
1398                                    String columnValue = newTypeSettingsProperties.getProperty(
1399                                            columnId);
1400    
1401                                    String[] portletIds = StringUtil.split(columnValue);
1402    
1403                                    if (!previousColumns.contains(columnId)) {
1404                                            newPortletIds = ArrayUtil.append(newPortletIds, portletIds);
1405                                    }
1406                                    else {
1407                                            String[] previousPortletIds = StringUtil.split(
1408                                                    previousTypeSettingsProperties.getProperty(columnId));
1409    
1410                                            portletIds = appendPortletIds(
1411                                                    previousPortletIds, portletIds, portletsMergeMode);
1412    
1413                                            previousTypeSettingsProperties.setProperty(
1414                                                    columnId, StringUtil.merge(portletIds));
1415                                    }
1416                            }
1417    
1418                            // Add portlets in non-existent column to the first column
1419    
1420                            String columnId = previousColumns.get(0);
1421    
1422                            String[] portletIds = StringUtil.split(
1423                                    previousTypeSettingsProperties.getProperty(columnId));
1424    
1425                            appendPortletIds(portletIds, newPortletIds, portletsMergeMode);
1426    
1427                            previousTypeSettingsProperties.setProperty(
1428                                    columnId, StringUtil.merge(portletIds));
1429    
1430                            layout.setTypeSettings(previousTypeSettingsProperties.toString());
1431                    }
1432                    catch (IOException ioe) {
1433                            layout.setTypeSettings(newTypeSettings);
1434                    }
1435            }
1436    
1437            private static Log _log = LogFactoryUtil.getLog(LayoutImporter.class);
1438    
1439            private static MethodHandler _loadThemesMethodHandler = new MethodHandler(
1440                    new MethodKey(ThemeLoaderFactory.class.getName(), "loadThemes"));
1441    
1442            private PermissionImporter _permissionImporter = new PermissionImporter();
1443            private PortletImporter _portletImporter = new PortletImporter();
1444    
1445    }