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