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