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