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