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