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<String> existingLayoutUuids = new HashSet<String>();
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                                            existingLayoutUuids.add(layout.getUuid());
200                                    }
201                            }
202                    }
203                    else {
204                            for (Layout layout : newLayouts) {
205                                    existingLayoutUuids.add(layout.getUuid());
206                            }
207                    }
208    
209                    if (_log.isDebugEnabled() && !existingLayoutUuids.isEmpty()) {
210                            _log.debug("Delete missing layouts");
211                    }
212    
213                    for (Layout layout : previousLayouts) {
214                            if (!existingLayoutUuids.contains(layout.getUuid())) {
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                    layoutSet = LayoutSetLocalServiceUtil.updatePageCount(
793                            groupId, privateLayout);
794    
795                    if (_log.isInfoEnabled()) {
796                            _log.info("Importing layouts takes " + stopWatch.getTime() + " ms");
797                    }
798    
799                    // Site
800    
801                    GroupLocalServiceUtil.updateSite(groupId, true);
802    
803                    // Web content layout type
804    
805                    for (Layout layout : newLayouts) {
806                            UnicodeProperties typeSettingsProperties =
807                                    layout.getTypeSettingsProperties();
808    
809                            String articleId = typeSettingsProperties.getProperty("article-id");
810    
811                            if (Validator.isNotNull(articleId)) {
812                                    Map<String, String> articleIds =
813                                            (Map<String, String>)portletDataContext.
814                                                    getNewPrimaryKeysMap(
815                                                            JournalArticle.class + ".articleId");
816    
817                                    typeSettingsProperties.setProperty(
818                                            "article-id",
819                                            MapUtil.getString(articleIds, articleId, articleId));
820    
821                                    LayoutUtil.update(layout);
822                            }
823                    }
824    
825                    // Last merge time for layout set prototypes
826    
827                    if (layoutsImportMode.equals(
828                                    PortletDataHandlerKeys.
829                                            LAYOUTS_IMPORT_MODE_CREATED_FROM_PROTOTYPE)) {
830    
831                            UnicodeProperties settingsProperties =
832                                    layoutSet.getSettingsProperties();
833    
834                            settingsProperties.setProperty(
835                                    "last-merge-time", String.valueOf(System.currentTimeMillis()));
836    
837                            LayoutSetLocalServiceUtil.updateLayoutSet(layoutSet);
838                    }
839    
840                    zipReader.close();
841            }
842    
843            protected void fixTypeSettings(Layout layout) throws Exception {
844                    if (!layout.isTypeURL()) {
845                            return;
846                    }
847    
848                    UnicodeProperties typeSettings = layout.getTypeSettingsProperties();
849    
850                    String url = GetterUtil.getString(typeSettings.getProperty("url"));
851    
852                    String friendlyURLPrivateGroupPath =
853                            PropsValues.LAYOUT_FRIENDLY_URL_PRIVATE_GROUP_SERVLET_MAPPING;
854                    String friendlyURLPrivateUserPath =
855                            PropsValues.LAYOUT_FRIENDLY_URL_PRIVATE_USER_SERVLET_MAPPING;
856                    String friendlyURLPublicPath =
857                            PropsValues.LAYOUT_FRIENDLY_URL_PUBLIC_SERVLET_MAPPING;
858    
859                    if (!url.startsWith(friendlyURLPrivateGroupPath) &&
860                            !url.startsWith(friendlyURLPrivateUserPath) &&
861                            !url.startsWith(friendlyURLPublicPath)) {
862    
863                            return;
864                    }
865    
866                    int x = url.indexOf(CharPool.SLASH, 1);
867    
868                    if (x == -1) {
869                            return;
870                    }
871    
872                    int y = url.indexOf(CharPool.SLASH, x + 1);
873    
874                    if (y == -1) {
875                            return;
876                    }
877    
878                    String friendlyURL = url.substring(x, y);
879    
880                    if (!friendlyURL.equals(LayoutExporter.SAME_GROUP_FRIENDLY_URL)) {
881                            return;
882                    }
883    
884                    Group group = layout.getGroup();
885    
886                    typeSettings.setProperty(
887                            "url",
888                            url.substring(0, x) + group.getFriendlyURL() + url.substring(y));
889            }
890    
891            protected String getLayoutSetPrototype(
892                    PortletDataContext portletDataContext, String layoutSetPrototypeUuid) {
893    
894                    StringBundler sb = new StringBundler(3);
895    
896                    sb.append(portletDataContext.getSourceRootPath());
897                    sb.append("/layout-set-prototype/");
898                    sb.append(layoutSetPrototypeUuid);
899    
900                    return sb.toString();
901            }
902    
903            protected void importJournalArticle(
904                            PortletDataContext portletDataContext, Layout layout,
905                            Element layoutElement)
906                    throws Exception {
907    
908                    UnicodeProperties typeSettingsProperties =
909                            layout.getTypeSettingsProperties();
910    
911                    String articleId = typeSettingsProperties.getProperty(
912                            "article-id", StringPool.BLANK);
913    
914                    if (Validator.isNull(articleId)) {
915                            return;
916                    }
917    
918                    JournalPortletDataHandlerImpl.importReferencedData(
919                            portletDataContext, layoutElement);
920    
921                    Element structureElement = layoutElement.element("structure");
922    
923                    if (structureElement != null) {
924                            JournalPortletDataHandlerImpl.importStructure(
925                                    portletDataContext, structureElement);
926                    }
927    
928                    Element templateElement = layoutElement.element("template");
929    
930                    if (templateElement != null) {
931                            JournalPortletDataHandlerImpl.importTemplate(
932                                    portletDataContext, templateElement);
933                    }
934    
935                    Element articleElement = layoutElement.element("article");
936    
937                    if (articleElement != null) {
938                            JournalPortletDataHandlerImpl.importArticle(
939                                    portletDataContext, articleElement);
940                    }
941    
942                    Map<String, String> articleIds =
943                            (Map<String, String>)portletDataContext.getNewPrimaryKeysMap(
944                                    JournalArticle.class + ".articleId");
945    
946                    articleId = MapUtil.getString(articleIds, articleId, articleId);
947    
948                    typeSettingsProperties.setProperty("article-id", articleId);
949    
950                    JournalContentSearchLocalServiceUtil.updateContentSearch(
951                            portletDataContext.getScopeGroupId(), layout.isPrivateLayout(),
952                            layout.getLayoutId(), StringPool.BLANK, articleId, true);
953            }
954    
955            protected void importLayout(
956                            PortletDataContext portletDataContext, User user,
957                            LayoutCache layoutCache, List<Layout> previousLayouts,
958                            List<Layout> newLayouts, Map<Long, Layout> newLayoutsMap,
959                            String portletsMergeMode, String themeId, String colorSchemeId,
960                            String layoutsImportMode, boolean privateLayout,
961                            boolean importPermissions, boolean importPublicLayoutPermissions,
962                            boolean importThemeSettings, Element rootElement,
963                            Element layoutElement)
964                    throws Exception {
965    
966                    long groupId = portletDataContext.getGroupId();
967    
968                    String layoutUuid = GetterUtil.getString(
969                            layoutElement.attributeValue("layout-uuid"));
970    
971                    long layoutId = GetterUtil.getInteger(
972                            layoutElement.attributeValue("layout-id"));
973    
974                    long oldLayoutId = layoutId;
975    
976                    boolean deleteLayout = GetterUtil.getBoolean(
977                            layoutElement.attributeValue("delete"));
978    
979                    if (deleteLayout) {
980                            Layout layout = LayoutLocalServiceUtil.fetchLayoutByUuidAndGroupId(
981                                    layoutUuid, groupId);
982    
983                            if (layout != null) {
984                                    newLayoutsMap.put(oldLayoutId, layout);
985    
986                                    ServiceContext serviceContext =
987                                            ServiceContextThreadLocal.getServiceContext();
988    
989                                    LayoutLocalServiceUtil.deleteLayout(
990                                            layout, false, serviceContext);
991                            }
992    
993                            return;
994                    }
995    
996                    String path = layoutElement.attributeValue("path");
997    
998                    if (!portletDataContext.isPathNotProcessed(path)) {
999                            return;
1000                    }
1001    
1002                    Layout layout = (Layout)portletDataContext.getZipEntryAsObject(path);
1003    
1004                    Layout existingLayout = null;
1005                    Layout importedLayout = null;
1006    
1007                    String friendlyURL = layout.getFriendlyURL();
1008    
1009                    if (layoutsImportMode.equals(
1010                                    PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE_ADD_AS_NEW)) {
1011    
1012                            layoutId = LayoutLocalServiceUtil.getNextLayoutId(
1013                                    groupId, privateLayout);
1014                            friendlyURL = StringPool.SLASH + layoutId;
1015                    }
1016                    else if (layoutsImportMode.equals(
1017                                            PortletDataHandlerKeys.
1018                                                    LAYOUTS_IMPORT_MODE_MERGE_BY_LAYOUT_NAME)) {
1019    
1020                            Locale locale = LocaleUtil.getDefault();
1021    
1022                            String localizedName = layout.getName(locale);
1023    
1024                            for (Layout curLayout : previousLayouts) {
1025                                    if (localizedName.equals(curLayout.getName(locale)) ||
1026                                            friendlyURL.equals(curLayout.getFriendlyURL())) {
1027    
1028                                            existingLayout = curLayout;
1029    
1030                                            break;
1031                                    }
1032                            }
1033    
1034                            if (existingLayout == null) {
1035                                    layoutId = LayoutLocalServiceUtil.getNextLayoutId(
1036                                            groupId, privateLayout);
1037                            }
1038                    }
1039                    else if (layoutsImportMode.equals(
1040                                            PortletDataHandlerKeys.
1041                                                    LAYOUTS_IMPORT_MODE_CREATED_FROM_PROTOTYPE)) {
1042    
1043                            existingLayout = LayoutUtil.fetchByG_P_SPLU(
1044                                    groupId, privateLayout, layout.getUuid());
1045    
1046                            if (SitesUtil.isLayoutModifiedSinceLastMerge(existingLayout)) {
1047                                    newLayoutsMap.put(oldLayoutId, existingLayout);
1048    
1049                                    return;
1050                            }
1051                    }
1052                    else {
1053    
1054                            // The default behaviour of import mode is
1055                            // PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE_MERGE_BY_LAYOUT_UUID
1056    
1057                            existingLayout = LayoutUtil.fetchByUUID_G(
1058                                    layout.getUuid(), groupId);
1059    
1060                            if (existingLayout == null) {
1061                                    existingLayout = LayoutUtil.fetchByG_P_F(
1062                                            groupId, privateLayout, friendlyURL);
1063                            }
1064    
1065                            if (existingLayout == null) {
1066                                    layoutId = LayoutLocalServiceUtil.getNextLayoutId(
1067                                            groupId, privateLayout);
1068                            }
1069                    }
1070    
1071                    if (_log.isDebugEnabled()) {
1072                            if (existingLayout == null) {
1073                                    _log.debug(
1074                                            "Layout with {groupId=" + groupId + ",privateLayout=" +
1075                                                    privateLayout + ",layoutId=" + layoutId +
1076                                                            "} does not exist");
1077                            }
1078                            else {
1079                                    _log.debug(
1080                                            "Layout with {groupId=" + groupId + ",privateLayout=" +
1081                                                    privateLayout + ",layoutId=" + layoutId + "} exists");
1082                            }
1083                    }
1084    
1085                    if (existingLayout == null) {
1086                            long plid = CounterLocalServiceUtil.increment();
1087    
1088                            importedLayout = LayoutUtil.create(plid);
1089    
1090                            if (layoutsImportMode.equals(
1091                                            PortletDataHandlerKeys.
1092                                                    LAYOUTS_IMPORT_MODE_CREATED_FROM_PROTOTYPE)) {
1093    
1094                                    importedLayout.setSourcePrototypeLayoutUuid(layout.getUuid());
1095    
1096                                    layoutId = LayoutLocalServiceUtil.getNextLayoutId(
1097                                            groupId, privateLayout);
1098                            }
1099                            else {
1100                                    importedLayout.setCreateDate(layout.getCreateDate());
1101                                    importedLayout.setModifiedDate(layout.getModifiedDate());
1102                                    importedLayout.setLayoutPrototypeUuid(
1103                                            layout.getLayoutPrototypeUuid());
1104                                    importedLayout.setLayoutPrototypeLinkEnabled(
1105                                            layout.isLayoutPrototypeLinkEnabled());
1106                                    importedLayout.setSourcePrototypeLayoutUuid(
1107                                            layout.getSourcePrototypeLayoutUuid());
1108                            }
1109    
1110                            importedLayout.setUuid(layout.getUuid());
1111                            importedLayout.setGroupId(groupId);
1112                            importedLayout.setPrivateLayout(privateLayout);
1113                            importedLayout.setLayoutId(layoutId);
1114    
1115                            // Resources
1116    
1117                            boolean addGroupPermissions = true;
1118    
1119                            Group group = importedLayout.getGroup();
1120    
1121                            if (privateLayout && group.isUser()) {
1122                                    addGroupPermissions = false;
1123                            }
1124    
1125                            boolean addGuestPermissions = false;
1126    
1127                            if (!privateLayout || layout.isTypeControlPanel()) {
1128                                    addGuestPermissions = true;
1129                            }
1130    
1131                            ResourceLocalServiceUtil.addResources(
1132                                    user.getCompanyId(), groupId, user.getUserId(),
1133                                    Layout.class.getName(), importedLayout.getPlid(), false,
1134                                    addGroupPermissions, addGuestPermissions);
1135    
1136                            LayoutSet layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
1137                                    groupId, privateLayout);
1138    
1139                            importedLayout.setLayoutSet(layoutSet);
1140                    }
1141                    else {
1142                            importedLayout = existingLayout;
1143                    }
1144    
1145                    newLayoutsMap.put(oldLayoutId, importedLayout);
1146    
1147                    long parentLayoutId = layout.getParentLayoutId();
1148    
1149                    Node parentLayoutNode = rootElement.selectSingleNode(
1150                            "./layouts/layout[@layout-id='" + parentLayoutId + "']");
1151    
1152                    String parentLayoutUuid = GetterUtil.getString(
1153                            layoutElement.attributeValue("parent-layout-uuid"));
1154    
1155                    if ((parentLayoutId != LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) &&
1156                            (parentLayoutNode != null)) {
1157    
1158                            importLayout(
1159                                    portletDataContext, user, layoutCache, previousLayouts,
1160                                    newLayouts, newLayoutsMap, portletsMergeMode, themeId,
1161                                    colorSchemeId, layoutsImportMode, privateLayout,
1162                                    importPermissions, importPublicLayoutPermissions,
1163                                    importThemeSettings, rootElement, (Element)parentLayoutNode);
1164    
1165                            Layout parentLayout = newLayoutsMap.get(parentLayoutId);
1166    
1167                            parentLayoutId = parentLayout.getLayoutId();
1168                    }
1169                    else if (Validator.isNotNull(parentLayoutUuid)) {
1170                            Layout parentLayout =
1171                                    LayoutLocalServiceUtil.getLayoutByUuidAndGroupId(
1172                                            parentLayoutUuid, groupId);
1173    
1174                            parentLayoutId = parentLayout.getLayoutId();
1175                    }
1176    
1177                    if (_log.isDebugEnabled()) {
1178                            _log.debug(
1179                                    "Importing layout with layout id " + layoutId +
1180                                            " and parent layout id " + parentLayoutId);
1181                    }
1182    
1183                    importedLayout.setCompanyId(user.getCompanyId());
1184                    importedLayout.setParentLayoutId(parentLayoutId);
1185                    importedLayout.setName(layout.getName());
1186                    importedLayout.setTitle(layout.getTitle());
1187                    importedLayout.setDescription(layout.getDescription());
1188                    importedLayout.setKeywords(layout.getKeywords());
1189                    importedLayout.setRobots(layout.getRobots());
1190                    importedLayout.setType(layout.getType());
1191    
1192                    if (layout.isTypeArticle()) {
1193                            importJournalArticle(portletDataContext, layout, layoutElement);
1194    
1195                            importedLayout.setTypeSettings(layout.getTypeSettings());
1196                    }
1197                    else if (layout.isTypePortlet() &&
1198                                     Validator.isNotNull(layout.getTypeSettings()) &&
1199                                     !portletsMergeMode.equals(
1200                                             PortletDataHandlerKeys.PORTLETS_MERGE_MODE_REPLACE)) {
1201    
1202                            mergePortlets(
1203                                    importedLayout, layout.getTypeSettings(), portletsMergeMode);
1204                    }
1205                    else if (layout.isTypeLinkToLayout()) {
1206                            UnicodeProperties typeSettingsProperties =
1207                                    layout.getTypeSettingsProperties();
1208    
1209                            long linkToLayoutId = GetterUtil.getLong(
1210                                    typeSettingsProperties.getProperty(
1211                                            "linkToLayoutId", StringPool.BLANK));
1212    
1213                            if (linkToLayoutId > 0) {
1214                                    Node linkedLayoutNode = rootElement.selectSingleNode(
1215                                            "./layouts/layout[@layout-id='" + linkToLayoutId + "']");
1216    
1217                                    if (linkedLayoutNode != null) {
1218                                            importLayout(
1219                                                    portletDataContext, user, layoutCache, previousLayouts,
1220                                                    newLayouts, newLayoutsMap, portletsMergeMode, themeId,
1221                                                    colorSchemeId, layoutsImportMode, privateLayout,
1222                                                    importPermissions, importPublicLayoutPermissions,
1223                                                    importThemeSettings, rootElement,
1224                                                    (Element)linkedLayoutNode);
1225    
1226                                            Layout linkedLayout = newLayoutsMap.get(linkToLayoutId);
1227    
1228                                            typeSettingsProperties.setProperty(
1229                                                    "privateLayout",
1230                                                    String.valueOf(linkedLayout.getPrivateLayout()));
1231                                            typeSettingsProperties.setProperty(
1232                                                    "linkToLayoutId",
1233                                                    String.valueOf(linkedLayout.getLayoutId()));
1234                                    }
1235                                    else {
1236                                            if (_log.isWarnEnabled()) {
1237                                                    StringBundler sb = new StringBundler();
1238    
1239                                                    sb.append("Unable to link layout with friendly URL ");
1240                                                    sb.append(layout.getFriendlyURL());
1241                                                    sb.append(" and layout id ");
1242                                                    sb.append(layout.getLayoutId());
1243                                                    sb.append(" to layout with layout id ");
1244                                                    sb.append(linkToLayoutId);
1245    
1246                                                    _log.warn(sb.toString());
1247                                            }
1248                                    }
1249                            }
1250    
1251                            importedLayout.setTypeSettings(layout.getTypeSettings());
1252                    }
1253                    else {
1254                            importedLayout.setTypeSettings(layout.getTypeSettings());
1255                    }
1256    
1257                    importedLayout.setHidden(layout.isHidden());
1258                    importedLayout.setFriendlyURL(friendlyURL);
1259    
1260                    if (importThemeSettings) {
1261                            importedLayout.setThemeId(layout.getThemeId());
1262                            importedLayout.setColorSchemeId(layout.getColorSchemeId());
1263                    }
1264                    else {
1265                            importedLayout.setThemeId(StringPool.BLANK);
1266                            importedLayout.setColorSchemeId(StringPool.BLANK);
1267                    }
1268    
1269                    importedLayout.setWapThemeId(layout.getWapThemeId());
1270                    importedLayout.setWapColorSchemeId(layout.getWapColorSchemeId());
1271                    importedLayout.setCss(layout.getCss());
1272                    importedLayout.setPriority(layout.getPriority());
1273                    importedLayout.setLayoutPrototypeUuid(layout.getLayoutPrototypeUuid());
1274                    importedLayout.setLayoutPrototypeLinkEnabled(
1275                            layout.isLayoutPrototypeLinkEnabled());
1276    
1277                    StagingUtil.updateLastImportSettings(
1278                            layoutElement, importedLayout, portletDataContext);
1279    
1280                    fixTypeSettings(importedLayout);
1281    
1282                    importedLayout.setIconImage(false);
1283    
1284                    if (layout.isIconImage()) {
1285                            String iconImagePath = layoutElement.elementText("icon-image-path");
1286    
1287                            byte[] iconBytes = portletDataContext.getZipEntryAsByteArray(
1288                                    iconImagePath);
1289    
1290                            if ((iconBytes != null) && (iconBytes.length > 0)) {
1291                                    importedLayout.setIconImage(true);
1292    
1293                                    if (importedLayout.getIconImageId() == 0) {
1294                                            long iconImageId = CounterLocalServiceUtil.increment();
1295    
1296                                            importedLayout.setIconImageId(iconImageId);
1297                                    }
1298    
1299                                    ImageLocalServiceUtil.updateImage(
1300                                            importedLayout.getIconImageId(), iconBytes);
1301                            }
1302                    }
1303                    else {
1304                            ImageLocalServiceUtil.deleteImage(importedLayout.getIconImageId());
1305                    }
1306    
1307                    ServiceContext serviceContext = portletDataContext.createServiceContext(
1308                            layoutElement, importedLayout, null);
1309    
1310                    importedLayout.setExpandoBridgeAttributes(serviceContext);
1311    
1312                    LayoutUtil.update(importedLayout);
1313    
1314                    portletDataContext.setPlid(importedLayout.getPlid());
1315                    portletDataContext.setOldPlid(layout.getPlid());
1316    
1317                    newLayouts.add(importedLayout);
1318    
1319                    // Layout permissions
1320    
1321                    if (importPermissions) {
1322                            _permissionImporter.importLayoutPermissions(
1323                                    layoutCache, portletDataContext.getCompanyId(), groupId,
1324                                    user.getUserId(), importedLayout, layoutElement, rootElement);
1325                    }
1326    
1327                    if (importPublicLayoutPermissions) {
1328                            String resourceName = Layout.class.getName();
1329                            String resourcePrimKey = String.valueOf(importedLayout.getPlid());
1330    
1331                            Role guestRole = RoleLocalServiceUtil.getRole(
1332                                    importedLayout.getCompanyId(), RoleConstants.GUEST);
1333    
1334                            ResourcePermissionLocalServiceUtil.setResourcePermissions(
1335                                    importedLayout.getCompanyId(), resourceName,
1336                                    ResourceConstants.SCOPE_INDIVIDUAL, resourcePrimKey,
1337                                    guestRole.getRoleId(), new String[] {ActionKeys.VIEW});
1338                    }
1339    
1340                    _portletImporter.importPortletData(
1341                            portletDataContext, PortletKeys.LAYOUT_CONFIGURATION, null,
1342                            layoutElement);
1343            }
1344    
1345            protected void importLayoutSetPrototype(
1346                            PortletDataContext portletDataContext, User user,
1347                            String layoutSetPrototypeUuid, ServiceContext serviceContext)
1348                    throws PortalException, SystemException {
1349    
1350                    String path = getLayoutSetPrototype(
1351                            portletDataContext, layoutSetPrototypeUuid);
1352    
1353                    LayoutSetPrototype layoutSetPrototype = null;
1354    
1355                    try {
1356                            layoutSetPrototype =
1357                                    LayoutSetPrototypeLocalServiceUtil.
1358                                            getLayoutSetPrototypeByUuidAndCompanyId(
1359                                                    layoutSetPrototypeUuid, serviceContext.getCompanyId());
1360                    }
1361                    catch (NoSuchLayoutSetPrototypeException nslspe) {
1362                    }
1363    
1364                    if (layoutSetPrototype == null) {
1365                            layoutSetPrototype =
1366                                    (LayoutSetPrototype)portletDataContext.getZipEntryAsObject(
1367                                            path.concat(".xml"));
1368    
1369                            serviceContext.setUuid(layoutSetPrototypeUuid);
1370    
1371                            layoutSetPrototype =
1372                                    LayoutSetPrototypeLocalServiceUtil.addLayoutSetPrototype(
1373                                            user.getUserId(), user.getCompanyId(),
1374                                            layoutSetPrototype.getNameMap(),
1375                                            layoutSetPrototype.getDescription(),
1376                                            layoutSetPrototype.getActive(), true, serviceContext);
1377                    }
1378    
1379                    InputStream inputStream = portletDataContext.getZipEntryAsInputStream(
1380                            path.concat(".lar"));
1381    
1382                    SitesUtil.importLayoutSetPrototype(
1383                            layoutSetPrototype, inputStream, serviceContext);
1384            }
1385    
1386            protected String importTheme(LayoutSet layoutSet, InputStream themeZip)
1387                    throws Exception {
1388    
1389                    ThemeLoader themeLoader = ThemeLoaderFactory.getDefaultThemeLoader();
1390    
1391                    if (themeLoader == null) {
1392                            _log.error("No theme loaders are deployed");
1393    
1394                            return null;
1395                    }
1396    
1397                    ZipReader zipReader = ZipReaderFactoryUtil.getZipReader(themeZip);
1398    
1399                    String lookAndFeelXML = zipReader.getEntryAsString(
1400                            "liferay-look-and-feel.xml");
1401    
1402                    String themeId = String.valueOf(layoutSet.getGroupId());
1403    
1404                    if (layoutSet.isPrivateLayout()) {
1405                            themeId += "-private";
1406                    }
1407                    else {
1408                            themeId += "-public";
1409                    }
1410    
1411                    if (PropsValues.THEME_LOADER_NEW_THEME_ID_ON_IMPORT) {
1412                            Date now = new Date();
1413    
1414                            themeId += "-" + Time.getShortTimestamp(now);
1415                    }
1416    
1417                    String themeName = themeId;
1418    
1419                    lookAndFeelXML = StringUtil.replace(
1420                            lookAndFeelXML,
1421                            new String[] {
1422                                    "[$GROUP_ID$]", "[$THEME_ID$]", "[$THEME_NAME$]"
1423                            },
1424                            new String[] {
1425                                    String.valueOf(layoutSet.getGroupId()), themeId, themeName
1426                            }
1427                    );
1428    
1429                    FileUtil.deltree(
1430                            themeLoader.getFileStorage() + StringPool.SLASH + themeId);
1431    
1432                    List<String> zipEntries = zipReader.getEntries();
1433    
1434                    for (String zipEntry : zipEntries) {
1435                            String key = zipEntry;
1436    
1437                            if (key.equals("liferay-look-and-feel.xml")) {
1438                                    FileUtil.write(
1439                                            themeLoader.getFileStorage() + StringPool.SLASH + themeId +
1440                                                    StringPool.SLASH + key,
1441                                            lookAndFeelXML.getBytes());
1442                            }
1443                            else {
1444                                    InputStream is = zipReader.getEntryAsInputStream(zipEntry);
1445    
1446                                    FileUtil.write(
1447                                            themeLoader.getFileStorage() + StringPool.SLASH + themeId +
1448                                                    StringPool.SLASH + key,
1449                                            is);
1450                            }
1451                    }
1452    
1453                    themeLoader.loadThemes();
1454    
1455                    ClusterRequest clusterRequest = ClusterRequest.createMulticastRequest(
1456                            _loadThemesMethodHandler, true);
1457    
1458                    clusterRequest.setFireAndForget(true);
1459    
1460                    ClusterExecutorUtil.execute(clusterRequest);
1461    
1462                    themeId +=
1463                            PortletConstants.WAR_SEPARATOR +
1464                                    themeLoader.getServletContextName();
1465    
1466                    return PortalUtil.getJsSafePortletId(themeId);
1467            }
1468    
1469            protected void mergePortlets(
1470                    Layout layout, String newTypeSettings, String portletsMergeMode) {
1471    
1472                    try {
1473                            UnicodeProperties previousTypeSettingsProperties =
1474                                    layout.getTypeSettingsProperties();
1475    
1476                            LayoutTypePortlet previousLayoutType =
1477                                    (LayoutTypePortlet)layout.getLayoutType();
1478    
1479                            LayoutTemplate previousLayoutTemplate =
1480                                    previousLayoutType.getLayoutTemplate();
1481    
1482                            List<String> previousColumns = previousLayoutTemplate.getColumns();
1483    
1484                            UnicodeProperties newTypeSettingsProperties = new UnicodeProperties(
1485                                    true);
1486    
1487                            newTypeSettingsProperties.load(newTypeSettings);
1488    
1489                            String layoutTemplateId = newTypeSettingsProperties.getProperty(
1490                                    LayoutTypePortletConstants.LAYOUT_TEMPLATE_ID);
1491    
1492                            previousTypeSettingsProperties.setProperty(
1493                                    LayoutTypePortletConstants.LAYOUT_TEMPLATE_ID,
1494                                    layoutTemplateId);
1495    
1496                            String nestedColumnIds = newTypeSettingsProperties.getProperty(
1497                                    LayoutTypePortletConstants.NESTED_COLUMN_IDS);
1498    
1499                            if (Validator.isNotNull(nestedColumnIds)) {
1500                                    previousTypeSettingsProperties.setProperty(
1501                                            LayoutTypePortletConstants.NESTED_COLUMN_IDS,
1502                                            nestedColumnIds);
1503    
1504                                    String[] nestedColumnIdsArray = StringUtil.split(
1505                                            nestedColumnIds);
1506    
1507                                    for (String nestedColumnId : nestedColumnIdsArray) {
1508                                            String nestedColumnValue =
1509                                                    newTypeSettingsProperties.getProperty(nestedColumnId);
1510    
1511                                            previousTypeSettingsProperties.setProperty(
1512                                                    nestedColumnId, nestedColumnValue);
1513                                    }
1514                            }
1515    
1516                            LayoutTemplate newLayoutTemplate =
1517                                    LayoutTemplateLocalServiceUtil.getLayoutTemplate(
1518                                            layoutTemplateId, false, null);
1519    
1520                            String[] newPortletIds = new String[0];
1521    
1522                            for (String columnId : newLayoutTemplate.getColumns()) {
1523                                    String columnValue = newTypeSettingsProperties.getProperty(
1524                                            columnId);
1525    
1526                                    String[] portletIds = StringUtil.split(columnValue);
1527    
1528                                    if (!previousColumns.contains(columnId)) {
1529                                            newPortletIds = ArrayUtil.append(newPortletIds, portletIds);
1530                                    }
1531                                    else {
1532                                            String[] previousPortletIds = StringUtil.split(
1533                                                    previousTypeSettingsProperties.getProperty(columnId));
1534    
1535                                            portletIds = appendPortletIds(
1536                                                    previousPortletIds, portletIds, portletsMergeMode);
1537    
1538                                            previousTypeSettingsProperties.setProperty(
1539                                                    columnId, StringUtil.merge(portletIds));
1540                                    }
1541                            }
1542    
1543                            // Add portlets in non-existent column to the first column
1544    
1545                            String columnId = previousColumns.get(0);
1546    
1547                            String[] portletIds = StringUtil.split(
1548                                    previousTypeSettingsProperties.getProperty(columnId));
1549    
1550                            appendPortletIds(portletIds, newPortletIds, portletsMergeMode);
1551    
1552                            previousTypeSettingsProperties.setProperty(
1553                                    columnId, StringUtil.merge(portletIds));
1554    
1555                            layout.setTypeSettings(previousTypeSettingsProperties.toString());
1556                    }
1557                    catch (IOException ioe) {
1558                            layout.setTypeSettings(newTypeSettings);
1559                    }
1560            }
1561    
1562            protected void validateLayoutPrototypes(
1563                            long companyId, Element layoutsElement,
1564                            List<Element> layoutElements)
1565                    throws Exception {
1566    
1567                    List<Tuple> missingLayoutPrototypes = new ArrayList<Tuple>();
1568    
1569                    String layoutSetPrototypeUuid = layoutsElement.attributeValue(
1570                            "layout-set-prototype-uuid");
1571    
1572                    if (Validator.isNotNull(layoutSetPrototypeUuid)) {
1573                            try {
1574                                    LayoutSetPrototypeLocalServiceUtil.
1575                                            getLayoutSetPrototypeByUuidAndCompanyId(
1576                                                    layoutSetPrototypeUuid, companyId);
1577                            }
1578                            catch (NoSuchLayoutSetPrototypeException nlspe) {
1579                                    String layoutSetPrototypeName = layoutsElement.attributeValue(
1580                                            "layout-set-prototype-name");
1581    
1582                                    missingLayoutPrototypes.add(
1583                                            new Tuple(
1584                                                    LayoutSetPrototype.class.getName(),
1585                                                    layoutSetPrototypeUuid, layoutSetPrototypeName));
1586                            }
1587                    }
1588    
1589                    for (Element layoutElement : layoutElements) {
1590                            String layoutPrototypeUuid = GetterUtil.getString(
1591                                    layoutElement.attributeValue("layout-prototype-uuid"));
1592    
1593                            if (Validator.isNotNull(layoutPrototypeUuid)) {
1594                                    try {
1595                                            LayoutPrototypeLocalServiceUtil.
1596                                                    getLayoutPrototypeByUuidAndCompanyId(
1597                                                            layoutPrototypeUuid, companyId);
1598                                    }
1599                                    catch (NoSuchLayoutPrototypeException nslpe) {
1600                                            String layoutPrototypeName = GetterUtil.getString(
1601                                                    layoutElement.attributeValue("layout-prototype-name"));
1602    
1603                                            missingLayoutPrototypes.add(
1604                                                    new Tuple(
1605                                                            LayoutPrototype.class.getName(),
1606                                                            layoutPrototypeUuid, layoutPrototypeName));
1607                                    }
1608                            }
1609                    }
1610    
1611                    if (!missingLayoutPrototypes.isEmpty()) {
1612                            throw new LayoutPrototypeException(missingLayoutPrototypes);
1613                    }
1614            }
1615    
1616            private static Log _log = LogFactoryUtil.getLog(LayoutImporter.class);
1617    
1618            private static MethodHandler _loadThemesMethodHandler = new MethodHandler(
1619                    new MethodKey(ThemeLoaderFactory.class, "loadThemes"));
1620    
1621            private PermissionImporter _permissionImporter = new PermissionImporter();
1622            private PortletImporter _portletImporter = new PortletImporter();
1623    
1624    }