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