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.portal.LARFileException;
018    import com.liferay.portal.LARTypeException;
019    import com.liferay.portal.LayoutImportException;
020    import com.liferay.portal.LayoutPrototypeException;
021    import com.liferay.portal.LocaleException;
022    import com.liferay.portal.MissingReferenceException;
023    import com.liferay.portal.NoSuchLayoutException;
024    import com.liferay.portal.NoSuchLayoutPrototypeException;
025    import com.liferay.portal.NoSuchLayoutSetPrototypeException;
026    import com.liferay.portal.kernel.backgroundtask.BackgroundTaskThreadLocal;
027    import com.liferay.portal.kernel.cluster.ClusterExecutorUtil;
028    import com.liferay.portal.kernel.cluster.ClusterRequest;
029    import com.liferay.portal.kernel.language.LanguageUtil;
030    import com.liferay.portal.kernel.lar.ExportImportHelperUtil;
031    import com.liferay.portal.kernel.lar.ExportImportThreadLocal;
032    import com.liferay.portal.kernel.lar.ManifestSummary;
033    import com.liferay.portal.kernel.lar.MissingReference;
034    import com.liferay.portal.kernel.lar.MissingReferences;
035    import com.liferay.portal.kernel.lar.PortletDataContext;
036    import com.liferay.portal.kernel.lar.PortletDataContextFactoryUtil;
037    import com.liferay.portal.kernel.lar.PortletDataHandlerKeys;
038    import com.liferay.portal.kernel.lar.PortletDataHandlerStatusMessageSenderUtil;
039    import com.liferay.portal.kernel.lar.StagedModelDataHandlerUtil;
040    import com.liferay.portal.kernel.lar.UserIdStrategy;
041    import com.liferay.portal.kernel.log.Log;
042    import com.liferay.portal.kernel.log.LogFactoryUtil;
043    import com.liferay.portal.kernel.search.Indexer;
044    import com.liferay.portal.kernel.search.IndexerRegistryUtil;
045    import com.liferay.portal.kernel.util.ArrayUtil;
046    import com.liferay.portal.kernel.util.ColorSchemeFactoryUtil;
047    import com.liferay.portal.kernel.util.Constants;
048    import com.liferay.portal.kernel.util.FileUtil;
049    import com.liferay.portal.kernel.util.GetterUtil;
050    import com.liferay.portal.kernel.util.LocaleUtil;
051    import com.liferay.portal.kernel.util.MapUtil;
052    import com.liferay.portal.kernel.util.MethodHandler;
053    import com.liferay.portal.kernel.util.MethodKey;
054    import com.liferay.portal.kernel.util.ReleaseInfo;
055    import com.liferay.portal.kernel.util.StringPool;
056    import com.liferay.portal.kernel.util.StringUtil;
057    import com.liferay.portal.kernel.util.Time;
058    import com.liferay.portal.kernel.util.Tuple;
059    import com.liferay.portal.kernel.util.UnicodeProperties;
060    import com.liferay.portal.kernel.util.Validator;
061    import com.liferay.portal.kernel.xml.Attribute;
062    import com.liferay.portal.kernel.xml.Document;
063    import com.liferay.portal.kernel.xml.Element;
064    import com.liferay.portal.kernel.xml.SAXReaderUtil;
065    import com.liferay.portal.kernel.zip.ZipReader;
066    import com.liferay.portal.kernel.zip.ZipReaderFactoryUtil;
067    import com.liferay.portal.model.Group;
068    import com.liferay.portal.model.Layout;
069    import com.liferay.portal.model.LayoutConstants;
070    import com.liferay.portal.model.LayoutPrototype;
071    import com.liferay.portal.model.LayoutSet;
072    import com.liferay.portal.model.LayoutSetPrototype;
073    import com.liferay.portal.model.Portlet;
074    import com.liferay.portal.model.PortletConstants;
075    import com.liferay.portal.model.User;
076    import com.liferay.portal.security.permission.PermissionCacheUtil;
077    import com.liferay.portal.service.GroupLocalServiceUtil;
078    import com.liferay.portal.service.LayoutLocalServiceUtil;
079    import com.liferay.portal.service.LayoutPrototypeLocalServiceUtil;
080    import com.liferay.portal.service.LayoutSetLocalServiceUtil;
081    import com.liferay.portal.service.LayoutSetPrototypeLocalServiceUtil;
082    import com.liferay.portal.service.PortletLocalServiceUtil;
083    import com.liferay.portal.service.ServiceContext;
084    import com.liferay.portal.service.ServiceContextThreadLocal;
085    import com.liferay.portal.service.persistence.LayoutUtil;
086    import com.liferay.portal.service.persistence.UserUtil;
087    import com.liferay.portal.servlet.filters.cache.CacheUtil;
088    import com.liferay.portal.theme.ThemeLoader;
089    import com.liferay.portal.theme.ThemeLoaderFactory;
090    import com.liferay.portal.util.PortalUtil;
091    import com.liferay.portal.util.PropsValues;
092    import com.liferay.portlet.journal.model.JournalArticle;
093    import com.liferay.portlet.journalcontent.util.JournalContentUtil;
094    import com.liferay.portlet.sites.util.Sites;
095    
096    import java.io.File;
097    import java.io.InputStream;
098    
099    import java.util.ArrayList;
100    import java.util.Date;
101    import java.util.List;
102    import java.util.Locale;
103    import java.util.Map;
104    
105    import org.apache.commons.lang.time.StopWatch;
106    
107    /**
108     * @author Brian Wing Shun Chan
109     * @author Joel Kozikowski
110     * @author Charles May
111     * @author Raymond Aug??
112     * @author Jorge Ferrer
113     * @author Bruno Farache
114     * @author Wesley Gong
115     * @author Zsigmond Rab
116     * @author Douglas Wong
117     * @author Julio Camarero
118     * @author Zsolt Berentey
119     */
120    public class LayoutImporter {
121    
122            public void importLayouts(
123                            long userId, long groupId, boolean privateLayout,
124                            Map<String, String[]> parameterMap, File file)
125                    throws Exception {
126    
127                    try {
128                            ExportImportThreadLocal.setLayoutImportInProcess(true);
129    
130                            doImportLayouts(userId, groupId, privateLayout, parameterMap, file);
131                    }
132                    finally {
133                            ExportImportThreadLocal.setLayoutImportInProcess(false);
134    
135                            CacheUtil.clearCache();
136                            JournalContentUtil.clearCache();
137                            PermissionCacheUtil.clearCache();
138                    }
139            }
140    
141            public MissingReferences validateFile(
142                            long userId, long groupId, boolean privateLayout,
143                            Map<String, String[]> parameterMap, File file)
144                    throws Exception {
145    
146                    LayoutSet layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
147                            groupId, privateLayout);
148    
149                    ZipReader zipReader = ZipReaderFactoryUtil.getZipReader(file);
150    
151                    PortletDataContext portletDataContext =
152                            PortletDataContextFactoryUtil.createImportPortletDataContext(
153                                    layoutSet.getCompanyId(), groupId, parameterMap, null,
154                                    zipReader);
155    
156                    validateFile(portletDataContext);
157    
158                    MissingReferences missingReferences =
159                            ExportImportHelperUtil.validateMissingReferences(
160                                    userId, groupId, parameterMap, file);
161    
162                    Map<String, MissingReference> dependencyMissingReferences =
163                            missingReferences.getDependencyMissingReferences();
164    
165                    if (!dependencyMissingReferences.isEmpty()) {
166                            throw new MissingReferenceException(missingReferences);
167                    }
168    
169                    return missingReferences;
170            }
171    
172            protected void deleteMissingLayouts(
173                            List<String> sourceLayoutUuids, List<Layout> previousLayouts,
174                            ServiceContext serviceContext)
175                    throws Exception {
176    
177                    if (_log.isDebugEnabled() && !sourceLayoutUuids.isEmpty()) {
178                            _log.debug("Delete missing layouts");
179                    }
180    
181                    for (Layout layout : previousLayouts) {
182                            if (!sourceLayoutUuids.contains(layout.getUuid())) {
183                                    try {
184                                            LayoutLocalServiceUtil.deleteLayout(
185                                                    layout, false, serviceContext);
186                                    }
187                                    catch (NoSuchLayoutException nsle) {
188                                    }
189                            }
190                    }
191            }
192    
193            protected void doImportLayouts(
194                            long userId, long groupId, boolean privateLayout,
195                            Map<String, String[]> parameterMap, File file)
196                    throws Exception {
197    
198                    boolean deleteMissingLayouts = MapUtil.getBoolean(
199                            parameterMap, PortletDataHandlerKeys.DELETE_MISSING_LAYOUTS,
200                            Boolean.TRUE.booleanValue());
201                    boolean deletePortletData = MapUtil.getBoolean(
202                            parameterMap, PortletDataHandlerKeys.DELETE_PORTLET_DATA);
203                    boolean importCategories = MapUtil.getBoolean(
204                            parameterMap, PortletDataHandlerKeys.CATEGORIES);
205                    boolean importPermissions = MapUtil.getBoolean(
206                            parameterMap, PortletDataHandlerKeys.PERMISSIONS);
207                    boolean importTheme = MapUtil.getBoolean(
208                            parameterMap, PortletDataHandlerKeys.THEME);
209                    boolean importThemeSettings = MapUtil.getBoolean(
210                            parameterMap, PortletDataHandlerKeys.THEME_REFERENCE);
211                    boolean importLogo = MapUtil.getBoolean(
212                            parameterMap, PortletDataHandlerKeys.LOGO);
213                    boolean importLayoutSetSettings = MapUtil.getBoolean(
214                            parameterMap, PortletDataHandlerKeys.LAYOUT_SET_SETTINGS);
215    
216                    boolean layoutSetPrototypeLinkEnabled = MapUtil.getBoolean(
217                            parameterMap,
218                            PortletDataHandlerKeys.LAYOUT_SET_PROTOTYPE_LINK_ENABLED, true);
219    
220                    Group group = GroupLocalServiceUtil.getGroup(groupId);
221    
222                    if (group.isLayoutSetPrototype()) {
223                            layoutSetPrototypeLinkEnabled = false;
224                    }
225    
226                    String layoutsImportMode = MapUtil.getString(
227                            parameterMap, PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE,
228                            PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE_MERGE_BY_LAYOUT_UUID);
229                    String userIdStrategy = MapUtil.getString(
230                            parameterMap, PortletDataHandlerKeys.USER_ID_STRATEGY);
231    
232                    if (_log.isDebugEnabled()) {
233                            _log.debug("Delete portlet data " + deletePortletData);
234                            _log.debug("Import categories " + importCategories);
235                            _log.debug("Import permissions " + importPermissions);
236                            _log.debug("Import theme " + importTheme);
237                    }
238    
239                    StopWatch stopWatch = null;
240    
241                    if (_log.isInfoEnabled()) {
242                            stopWatch = new StopWatch();
243    
244                            stopWatch.start();
245                    }
246    
247                    LayoutCache layoutCache = new LayoutCache();
248    
249                    LayoutSet layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
250                            groupId, privateLayout);
251    
252                    long companyId = layoutSet.getCompanyId();
253    
254                    User user = UserUtil.findByPrimaryKey(userId);
255    
256                    UserIdStrategy strategy = _portletImporter.getUserIdStrategy(
257                            user, userIdStrategy);
258    
259                    if (BackgroundTaskThreadLocal.hasBackgroundTask()) {
260                            ManifestSummary manifestSummary =
261                                    ExportImportHelperUtil.getManifestSummary(
262                                            userId, groupId, parameterMap, file);
263    
264                            PortletDataHandlerStatusMessageSenderUtil.sendStatusMessage(
265                                    "layout", manifestSummary);
266                    }
267    
268                    ZipReader zipReader = ZipReaderFactoryUtil.getZipReader(file);
269    
270                    PortletDataContext portletDataContext =
271                            PortletDataContextFactoryUtil.createImportPortletDataContext(
272                                    companyId, groupId, parameterMap, strategy, zipReader);
273    
274                    portletDataContext.setPortetDataContextListener(
275                            new PortletDataContextListenerImpl(portletDataContext));
276    
277                    portletDataContext.setPrivateLayout(privateLayout);
278    
279                    // Zip
280    
281                    InputStream themeZip = null;
282    
283                    validateFile(portletDataContext);
284    
285                    // Company id
286    
287                    long sourceCompanyId = GetterUtil.getLong(
288                            _headerElement.attributeValue("company-id"));
289    
290                    portletDataContext.setSourceCompanyId(sourceCompanyId);
291    
292                    // Company group id
293    
294                    long sourceCompanyGroupId = GetterUtil.getLong(
295                            _headerElement.attributeValue("company-group-id"));
296    
297                    portletDataContext.setSourceCompanyGroupId(sourceCompanyGroupId);
298    
299                    // Group id
300    
301                    long sourceGroupId = GetterUtil.getLong(
302                            _headerElement.attributeValue("group-id"));
303    
304                    portletDataContext.setSourceGroupId(sourceGroupId);
305    
306                    // User personal site group id
307    
308                    long sourceUserPersonalSiteGroupId = GetterUtil.getLong(
309                            _headerElement.attributeValue("user-personal-site-group-id"));
310    
311                    portletDataContext.setSourceUserPersonalSiteGroupId(
312                            sourceUserPersonalSiteGroupId);
313    
314                    // Layout and layout set prototype
315    
316                    String layoutSetPrototypeUuid = _layoutsElement.attributeValue(
317                            "layout-set-prototype-uuid");
318    
319                    String larType = _headerElement.attributeValue("type");
320    
321                    if (group.isLayoutPrototype() && larType.equals("layout-prototype")) {
322                            deleteMissingLayouts = false;
323    
324                            LayoutPrototype layoutPrototype =
325                                    LayoutPrototypeLocalServiceUtil.getLayoutPrototype(
326                                            group.getClassPK());
327    
328                            String layoutPrototypeUuid = GetterUtil.getString(
329                                    _headerElement.attributeValue("type-uuid"));
330    
331                            LayoutPrototype existingLayoutPrototype = null;
332    
333                            if (Validator.isNotNull(layoutPrototypeUuid)) {
334                                    try {
335                                            existingLayoutPrototype =
336                                                    LayoutPrototypeLocalServiceUtil.
337                                                            getLayoutPrototypeByUuidAndCompanyId(
338                                                                    layoutPrototypeUuid, companyId);
339                                    }
340                                    catch (NoSuchLayoutPrototypeException nslpe) {
341                                    }
342                            }
343    
344                            if (existingLayoutPrototype == null) {
345                                    List<Layout> layouts =
346                                            LayoutLocalServiceUtil.getLayoutsByLayoutPrototypeUuid(
347                                                    layoutPrototype.getUuid());
348    
349                                    layoutPrototype.setUuid(layoutPrototypeUuid);
350    
351                                    LayoutPrototypeLocalServiceUtil.updateLayoutPrototype(
352                                            layoutPrototype);
353    
354                                    for (Layout layout : layouts) {
355                                            layout.setLayoutPrototypeUuid(layoutPrototypeUuid);
356    
357                                            LayoutLocalServiceUtil.updateLayout(layout);
358                                    }
359                            }
360                    }
361                    else if (group.isLayoutSetPrototype() &&
362                                     larType.equals("layout-set-prototype")) {
363    
364                            LayoutSetPrototype layoutSetPrototype =
365                                    LayoutSetPrototypeLocalServiceUtil.getLayoutSetPrototype(
366                                            group.getClassPK());
367    
368                            String importedLayoutSetPrototypeUuid = GetterUtil.getString(
369                                    _headerElement.attributeValue("type-uuid"));
370    
371                            LayoutSetPrototype existingLayoutSetPrototype = null;
372    
373                            if (Validator.isNotNull(importedLayoutSetPrototypeUuid)) {
374                                    try {
375                                            existingLayoutSetPrototype =
376                                                    LayoutSetPrototypeLocalServiceUtil.
377                                                            getLayoutSetPrototypeByUuidAndCompanyId(
378                                                                    importedLayoutSetPrototypeUuid, companyId);
379                                    }
380                                    catch (NoSuchLayoutSetPrototypeException nslspe) {
381                                    }
382                            }
383    
384                            if (existingLayoutSetPrototype == null) {
385                                    layoutSetPrototype.setUuid(importedLayoutSetPrototypeUuid);
386    
387                                    LayoutSetPrototypeLocalServiceUtil.updateLayoutSetPrototype(
388                                            layoutSetPrototype);
389                            }
390                    }
391                    else if (larType.equals("layout-set-prototype")) {
392                            layoutSetPrototypeUuid = GetterUtil.getString(
393                                    _headerElement.attributeValue("type-uuid"));
394                    }
395    
396                    ServiceContext serviceContext =
397                            ServiceContextThreadLocal.getServiceContext();
398    
399                    if (Validator.isNotNull(layoutSetPrototypeUuid)) {
400                            layoutSet.setLayoutSetPrototypeUuid(layoutSetPrototypeUuid);
401                            layoutSet.setLayoutSetPrototypeLinkEnabled(
402                                    layoutSetPrototypeLinkEnabled);
403    
404                            LayoutSetLocalServiceUtil.updateLayoutSet(layoutSet);
405                    }
406    
407                    // Look and feel
408    
409                    if (importTheme) {
410                            themeZip = portletDataContext.getZipEntryAsInputStream("theme.zip");
411                    }
412    
413                    // Look and feel
414    
415                    String themeId = layoutSet.getThemeId();
416                    String colorSchemeId = layoutSet.getColorSchemeId();
417    
418                    if (importThemeSettings) {
419                            Attribute themeIdAttribute = _headerElement.attribute("theme-id");
420    
421                            if (themeIdAttribute != null) {
422                                    themeId = themeIdAttribute.getValue();
423                            }
424    
425                            Attribute colorSchemeIdAttribute = _headerElement.attribute(
426                                    "color-scheme-id");
427    
428                            if (colorSchemeIdAttribute != null) {
429                                    colorSchemeId = colorSchemeIdAttribute.getValue();
430                            }
431                    }
432    
433                    if (importLogo) {
434                            String logoPath = _headerElement.attributeValue("logo-path");
435    
436                            byte[] iconBytes = portletDataContext.getZipEntryAsByteArray(
437                                    logoPath);
438    
439                            if ((iconBytes != null) && (iconBytes.length > 0)) {
440                                    File logo = null;
441    
442                                    try {
443                                            logo = FileUtil.createTempFile(iconBytes);
444    
445                                            LayoutSetLocalServiceUtil.updateLogo(
446                                                    groupId, privateLayout, true, logo);
447                                    }
448                                    finally {
449                                            FileUtil.delete(logo);
450                                    }
451                            }
452                            else {
453                                    LayoutSetLocalServiceUtil.updateLogo(
454                                            groupId, privateLayout, false, (File)null);
455                            }
456                    }
457    
458                    if (importLayoutSetSettings) {
459                            String settings = GetterUtil.getString(
460                                    _headerElement.elementText("settings"));
461    
462                            LayoutSetLocalServiceUtil.updateSettings(
463                                    groupId, privateLayout, settings);
464                    }
465    
466                    String css = GetterUtil.getString(_headerElement.elementText("css"));
467    
468                    if (themeZip != null) {
469                            String importThemeId = importTheme(layoutSet, themeZip);
470    
471                            if (importThemeId != null) {
472                                    themeId = importThemeId;
473                                    colorSchemeId =
474                                            ColorSchemeFactoryUtil.getDefaultRegularColorSchemeId();
475                            }
476    
477                            if (_log.isDebugEnabled()) {
478                                    _log.debug(
479                                            "Importing theme takes " + stopWatch.getTime() + " ms");
480                            }
481                    }
482    
483                    boolean wapTheme = false;
484    
485                    LayoutSetLocalServiceUtil.updateLookAndFeel(
486                            groupId, privateLayout, themeId, colorSchemeId, css, wapTheme);
487    
488                    // Read asset categories, asset tags, comments, locks, permissions, and
489                    // ratings entries to make them available to the data handlers through
490                    // the context
491    
492                    if (importPermissions) {
493                            _permissionImporter.readPortletDataPermissions(portletDataContext);
494                    }
495    
496                    _portletImporter.readAssetCategories(portletDataContext);
497                    _portletImporter.readAssetTags(portletDataContext);
498                    _portletImporter.readComments(portletDataContext);
499                    _portletImporter.readExpandoTables(portletDataContext);
500                    _portletImporter.readLocks(portletDataContext);
501                    _portletImporter.readRatingsEntries(portletDataContext);
502    
503                    // Layouts
504    
505                    List<Layout> previousLayouts = LayoutUtil.findByG_P(
506                            groupId, privateLayout);
507    
508                    // Remove layouts that were deleted from the layout set prototype
509    
510                    if (Validator.isNotNull(layoutSetPrototypeUuid) &&
511                            layoutSetPrototypeLinkEnabled) {
512    
513                            LayoutSetPrototype layoutSetPrototype =
514                                    LayoutSetPrototypeLocalServiceUtil.
515                                            getLayoutSetPrototypeByUuidAndCompanyId(
516                                                    layoutSetPrototypeUuid, companyId);
517    
518                            for (Layout layout : previousLayouts) {
519                                    String sourcePrototypeLayoutUuid =
520                                            layout.getSourcePrototypeLayoutUuid();
521    
522                                    if (Validator.isNull(layout.getSourcePrototypeLayoutUuid())) {
523                                            continue;
524                                    }
525    
526                                    Layout sourcePrototypeLayout = LayoutUtil.fetchByUUID_G_P(
527                                            sourcePrototypeLayoutUuid, layoutSetPrototype.getGroupId(),
528                                            true);
529    
530                                    if (sourcePrototypeLayout == null) {
531                                            LayoutLocalServiceUtil.deleteLayout(
532                                                    layout, false, serviceContext);
533                                    }
534                            }
535                    }
536    
537                    List<String> sourceLayoutsUuids = new ArrayList<String>();
538                    List<Layout> newLayouts = new ArrayList<Layout>();
539    
540                    if (_log.isDebugEnabled()) {
541                            if (_layoutElements.size() > 0) {
542                                    _log.debug("Importing layouts");
543                            }
544                    }
545    
546                    for (Element layoutElement : _layoutElements) {
547                            importLayout(
548                                    portletDataContext, sourceLayoutsUuids, newLayouts,
549                                    layoutElement);
550                    }
551    
552                    Element portletsElement = _rootElement.element("portlets");
553    
554                    List<Element> portletElements = portletsElement.elements("portlet");
555    
556                    // Delete portlet data
557    
558                    Map<Long, Layout> newLayoutsMap =
559                            (Map<Long, Layout>)portletDataContext.getNewPrimaryKeysMap(
560                                    Layout.class + ".layout");
561    
562                    if (deletePortletData) {
563                            if (_log.isDebugEnabled()) {
564                                    if (portletElements.size() > 0) {
565                                            _log.debug("Deleting portlet data");
566                                    }
567                            }
568    
569                            for (Element portletElement : portletElements) {
570                                    String portletId = portletElement.attributeValue("portlet-id");
571                                    long layoutId = GetterUtil.getLong(
572                                            portletElement.attributeValue("layout-id"));
573    
574                                    Layout layout = newLayoutsMap.get(layoutId);
575    
576                                    long plid = layout.getPlid();
577    
578                                    portletDataContext.setPlid(plid);
579    
580                                    _portletImporter.deletePortletData(
581                                            portletDataContext, portletId, plid);
582                            }
583                    }
584    
585                    // Import portlets
586    
587                    if (_log.isDebugEnabled()) {
588                            if (portletElements.size() > 0) {
589                                    _log.debug("Importing portlets");
590                            }
591                    }
592    
593                    for (Element portletElement : portletElements) {
594                            String portletPath = portletElement.attributeValue("path");
595                            String portletId = portletElement.attributeValue("portlet-id");
596                            long layoutId = GetterUtil.getLong(
597                                    portletElement.attributeValue("layout-id"));
598                            long oldPlid = GetterUtil.getLong(
599                                    portletElement.attributeValue("old-plid"));
600    
601                            Portlet portlet = PortletLocalServiceUtil.getPortletById(
602                                    portletDataContext.getCompanyId(), portletId);
603    
604                            if (!portlet.isActive() || portlet.isUndeployedPortlet()) {
605                                    continue;
606                            }
607    
608                            Layout layout = newLayoutsMap.get(layoutId);
609    
610                            long plid = LayoutConstants.DEFAULT_PLID;
611    
612                            if (layout != null) {
613                                    plid = layout.getPlid();
614                            }
615    
616                            layout = LayoutUtil.fetchByPrimaryKey(plid);
617    
618                            if ((layout == null) && !group.isCompany()) {
619                                    continue;
620                            }
621    
622                            portletDataContext.setPlid(plid);
623                            portletDataContext.setOldPlid(oldPlid);
624    
625                            Document portletDocument = SAXReaderUtil.read(
626                                    portletDataContext.getZipEntryAsString(portletPath));
627    
628                            portletElement = portletDocument.getRootElement();
629    
630                            // The order of the import is important. You must always import the
631                            // portlet preferences first, then the portlet data, then the
632                            // portlet permissions. The import of the portlet data assumes that
633                            // portlet preferences already exist.
634    
635                            _portletImporter.setPortletScope(
636                                    portletDataContext, portletElement);
637    
638                            long portletPreferencesGroupId = groupId;
639    
640                            Element portletDataElement = portletElement.element("portlet-data");
641    
642                            boolean[] importPortletControls = getImportPortletControls(
643                                    companyId, portletId, parameterMap, portletDataElement);
644    
645                            try {
646                                    if ((layout != null) && !group.isCompany()) {
647                                            portletPreferencesGroupId = layout.getGroupId();
648                                    }
649    
650                                    // Portlet preferences
651    
652                                    _portletImporter.importPortletPreferences(
653                                            portletDataContext, layoutSet.getCompanyId(),
654                                            portletPreferencesGroupId, layout, null, portletElement,
655                                            importPortletControls[2], importPortletControls[0],
656                                            importPortletControls[3], false, importPortletControls[1]);
657    
658                                    // Portlet data
659    
660                                    if (importPortletControls[1]) {
661                                            _portletImporter.importPortletData(
662                                                    portletDataContext, portletId, plid,
663                                                    portletDataElement);
664                                    }
665                            }
666                            finally {
667                                    _portletImporter.resetPortletScope(
668                                            portletDataContext, portletPreferencesGroupId);
669                            }
670    
671                            // Portlet permissions
672    
673                            if (importPermissions) {
674                                    _permissionImporter.importPortletPermissions(
675                                            layoutCache, companyId, groupId, userId, layout,
676                                            portletElement, portletId);
677                            }
678    
679                            // Archived setups
680    
681                            _portletImporter.importPortletPreferences(
682                                    portletDataContext, layoutSet.getCompanyId(), groupId, null,
683                                    null, portletElement, importPortletControls[2],
684                                    importPortletControls[0], importPortletControls[3], false,
685                                    importPortletControls[1]);
686                    }
687    
688                    if (importPermissions) {
689                            if (userId > 0) {
690                                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
691                                            User.class);
692    
693                                    indexer.reindex(userId);
694                            }
695                    }
696    
697                    // Asset links
698    
699                    _portletImporter.readAssetLinks(portletDataContext);
700    
701                    // Delete missing layouts
702    
703                    if (deleteMissingLayouts) {
704                            deleteMissingLayouts(
705                                    sourceLayoutsUuids, previousLayouts, serviceContext);
706                    }
707    
708                    // Page count
709    
710                    layoutSet = LayoutSetLocalServiceUtil.updatePageCount(
711                            groupId, privateLayout);
712    
713                    // Site
714    
715                    GroupLocalServiceUtil.updateSite(groupId, true);
716    
717                    // Last merge time must be the same for merged layouts and the layout
718                    // set
719    
720                    long lastMergeTime = System.currentTimeMillis();
721    
722                    for (Layout layout : newLayouts) {
723                            boolean modifiedTypeSettingsProperties = false;
724    
725                            UnicodeProperties typeSettingsProperties =
726                                    layout.getTypeSettingsProperties();
727    
728                            // Journal article layout type
729    
730                            String articleId = typeSettingsProperties.getProperty("article-id");
731    
732                            if (Validator.isNotNull(articleId)) {
733                                    Map<String, String> articleIds =
734                                            (Map<String, String>)portletDataContext.
735                                                    getNewPrimaryKeysMap(
736                                                            JournalArticle.class + ".articleId");
737    
738                                    typeSettingsProperties.setProperty(
739                                            "article-id",
740                                            MapUtil.getString(articleIds, articleId, articleId));
741    
742                                    modifiedTypeSettingsProperties = true;
743                            }
744    
745                            // Last merge time for layout
746    
747                            if (layoutsImportMode.equals(
748                                            PortletDataHandlerKeys.
749                                                    LAYOUTS_IMPORT_MODE_CREATED_FROM_PROTOTYPE)) {
750    
751                                    typeSettingsProperties.setProperty(
752                                            Sites.LAST_MERGE_TIME, String.valueOf(lastMergeTime));
753    
754                                    modifiedTypeSettingsProperties = true;
755                            }
756    
757                            if (modifiedTypeSettingsProperties) {
758                                    LayoutUtil.update(layout);
759                            }
760                    }
761    
762                    // Last merge time for layout set
763    
764                    if (layoutsImportMode.equals(
765                                    PortletDataHandlerKeys.
766                                            LAYOUTS_IMPORT_MODE_CREATED_FROM_PROTOTYPE)) {
767    
768                            UnicodeProperties settingsProperties =
769                                    layoutSet.getSettingsProperties();
770    
771                            String mergeFailFriendlyURLLayouts =
772                                    settingsProperties.getProperty(
773                                            Sites.MERGE_FAIL_FRIENDLY_URL_LAYOUTS);
774    
775                            if (Validator.isNull(mergeFailFriendlyURLLayouts)) {
776                                    settingsProperties.setProperty(
777                                            Sites.LAST_MERGE_TIME, String.valueOf(lastMergeTime));
778    
779                                    LayoutSetLocalServiceUtil.updateLayoutSet(layoutSet);
780                            }
781                    }
782    
783                    // Deletion system events
784    
785                    _deletionSystemEventImporter.importDeletionSystemEvents(
786                            portletDataContext);
787    
788                    if (_log.isInfoEnabled()) {
789                            _log.info("Importing layouts takes " + stopWatch.getTime() + " ms");
790                    }
791    
792                    zipReader.close();
793            }
794    
795            protected boolean[] getImportPortletControls(
796                            long companyId, String portletId,
797                            Map<String, String[]> parameterMap, Element portletDataElement)
798                    throws Exception {
799    
800                    boolean importPortletConfiguration = MapUtil.getBoolean(
801                            parameterMap, PortletDataHandlerKeys.PORTLET_CONFIGURATION);
802                    boolean importPortletConfigurationAll = MapUtil.getBoolean(
803                            parameterMap, PortletDataHandlerKeys.PORTLET_CONFIGURATION_ALL);
804                    boolean importPortletData = MapUtil.getBoolean(
805                            parameterMap, PortletDataHandlerKeys.PORTLET_DATA);
806                    boolean importPortletDataAll = MapUtil.getBoolean(
807                            parameterMap, PortletDataHandlerKeys.PORTLET_DATA_ALL);
808    
809                    if (_log.isDebugEnabled()) {
810                            _log.debug("Import portlet data " + importPortletData);
811                            _log.debug("Import all portlet data " + importPortletDataAll);
812                            _log.debug(
813                                    "Import portlet configuration " + importPortletConfiguration);
814                    }
815    
816                    boolean importCurPortletData = importPortletData;
817    
818                    String rootPortletId =
819                            ExportImportHelperUtil.getExportableRootPortletId(
820                                    companyId, portletId);
821    
822                    if (portletDataElement == null) {
823                            importCurPortletData = false;
824                    }
825                    else if (importPortletDataAll) {
826                            importCurPortletData = true;
827                    }
828                    else if (rootPortletId != null) {
829                            importCurPortletData =
830                                    importPortletData &&
831                                    MapUtil.getBoolean(
832                                            parameterMap,
833                                            PortletDataHandlerKeys.PORTLET_DATA +
834                                                    StringPool.UNDERLINE + rootPortletId);
835                    }
836    
837                    boolean importCurPortletArchivedSetups = importPortletConfiguration;
838                    boolean importCurPortletSetup = importPortletConfiguration;
839                    boolean importCurPortletUserPreferences = importPortletConfiguration;
840    
841                    if (importPortletConfigurationAll) {
842                            importCurPortletArchivedSetups =
843                                    MapUtil.getBoolean(
844                                            parameterMap,
845                                            PortletDataHandlerKeys.PORTLET_ARCHIVED_SETUPS_ALL);
846                            importCurPortletSetup =
847                                    MapUtil.getBoolean(
848                                            parameterMap, PortletDataHandlerKeys.PORTLET_SETUP_ALL);
849                            importCurPortletUserPreferences =
850                                    MapUtil.getBoolean(
851                                            parameterMap,
852                                            PortletDataHandlerKeys.PORTLET_USER_PREFERENCES_ALL);
853                    }
854                    else if (rootPortletId != null) {
855                            boolean importCurPortletConfiguration =
856                                    importPortletConfiguration &&
857                                    MapUtil.getBoolean(
858                                            parameterMap,
859                                            PortletDataHandlerKeys.PORTLET_CONFIGURATION +
860                                                    StringPool.UNDERLINE + rootPortletId);
861    
862                            importCurPortletArchivedSetups =
863                                    importCurPortletConfiguration &&
864                                    MapUtil.getBoolean(
865                                            parameterMap,
866                                            PortletDataHandlerKeys.PORTLET_ARCHIVED_SETUPS +
867                                                    StringPool.UNDERLINE + rootPortletId);
868                            importCurPortletSetup =
869                                    importCurPortletConfiguration &&
870                                    MapUtil.getBoolean(
871                                            parameterMap,
872                                            PortletDataHandlerKeys.PORTLET_SETUP +
873                                                    StringPool.UNDERLINE + rootPortletId);
874                            importCurPortletUserPreferences =
875                                    importCurPortletConfiguration &&
876                                    MapUtil.getBoolean(
877                                            parameterMap,
878                                            PortletDataHandlerKeys.PORTLET_USER_PREFERENCES +
879                                                    StringPool.UNDERLINE + rootPortletId);
880                    }
881    
882                    return new boolean[] {
883                            importCurPortletArchivedSetups, importCurPortletData,
884                            importCurPortletSetup, importCurPortletUserPreferences};
885            }
886    
887            protected void importLayout(
888                            PortletDataContext portletDataContext,
889                            List<String> sourceLayoutsUuids, List<Layout> newLayouts,
890                            Element layoutElement)
891                    throws Exception {
892    
893                    String action = layoutElement.attributeValue("action");
894    
895                    if (!action.equals(Constants.SKIP)) {
896                            StagedModelDataHandlerUtil.importStagedModel(
897                                    portletDataContext, layoutElement);
898    
899                            List<Layout> portletDataContextNewLayouts =
900                                    portletDataContext.getNewLayouts();
901    
902                            newLayouts.addAll(portletDataContextNewLayouts);
903    
904                            portletDataContextNewLayouts.clear();
905                    }
906    
907                    if (!action.equals(Constants.DELETE)) {
908                            sourceLayoutsUuids.add(layoutElement.attributeValue("uuid"));
909                    }
910            }
911    
912            protected String importTheme(LayoutSet layoutSet, InputStream themeZip)
913                    throws Exception {
914    
915                    ThemeLoader themeLoader = ThemeLoaderFactory.getDefaultThemeLoader();
916    
917                    if (themeLoader == null) {
918                            _log.error("No theme loaders are deployed");
919    
920                            return null;
921                    }
922    
923                    ZipReader zipReader = ZipReaderFactoryUtil.getZipReader(themeZip);
924    
925                    String lookAndFeelXML = zipReader.getEntryAsString(
926                            "liferay-look-and-feel.xml");
927    
928                    String themeId = String.valueOf(layoutSet.getGroupId());
929    
930                    if (layoutSet.isPrivateLayout()) {
931                            themeId += "-private";
932                    }
933                    else {
934                            themeId += "-public";
935                    }
936    
937                    if (PropsValues.THEME_LOADER_NEW_THEME_ID_ON_IMPORT) {
938                            Date now = new Date();
939    
940                            themeId += "-" + Time.getShortTimestamp(now);
941                    }
942    
943                    String themeName = themeId;
944    
945                    lookAndFeelXML = StringUtil.replace(
946                            lookAndFeelXML,
947                            new String[] {
948                                    "[$GROUP_ID$]", "[$THEME_ID$]", "[$THEME_NAME$]"
949                            },
950                            new String[] {
951                                    String.valueOf(layoutSet.getGroupId()), themeId, themeName
952                            }
953                    );
954    
955                    FileUtil.deltree(
956                            themeLoader.getFileStorage() + StringPool.SLASH + themeId);
957    
958                    List<String> zipEntries = zipReader.getEntries();
959    
960                    for (String zipEntry : zipEntries) {
961                            String key = zipEntry;
962    
963                            if (key.equals("liferay-look-and-feel.xml")) {
964                                    FileUtil.write(
965                                            themeLoader.getFileStorage() + StringPool.SLASH + themeId +
966                                                    StringPool.SLASH + key,
967                                            lookAndFeelXML.getBytes());
968                            }
969                            else {
970                                    InputStream is = zipReader.getEntryAsInputStream(zipEntry);
971    
972                                    FileUtil.write(
973                                            themeLoader.getFileStorage() + StringPool.SLASH + themeId +
974                                                    StringPool.SLASH + key,
975                                            is);
976                            }
977                    }
978    
979                    themeLoader.loadThemes();
980    
981                    ClusterRequest clusterRequest = ClusterRequest.createMulticastRequest(
982                            _loadThemesMethodHandler, true);
983    
984                    clusterRequest.setFireAndForget(true);
985    
986                    ClusterExecutorUtil.execute(clusterRequest);
987    
988                    themeId +=
989                            PortletConstants.WAR_SEPARATOR +
990                                    themeLoader.getServletContextName();
991    
992                    return PortalUtil.getJsSafePortletId(themeId);
993            }
994    
995            protected void readXML(PortletDataContext portletDataContext)
996                    throws Exception {
997    
998                    if ((_rootElement != null) && (_headerElement != null) &&
999                            (_layoutsElement != null) && (_layoutElements != null)) {
1000    
1001                            return;
1002                    }
1003    
1004                    String xml = portletDataContext.getZipEntryAsString("/manifest.xml");
1005    
1006                    if (xml == null) {
1007                            throw new LARFileException("manifest.xml not found in the LAR");
1008                    }
1009    
1010                    try {
1011                            Document document = SAXReaderUtil.read(xml);
1012    
1013                            _rootElement = document.getRootElement();
1014    
1015                            portletDataContext.setImportDataRootElement(_rootElement);
1016                    }
1017                    catch (Exception e) {
1018                            throw new LARFileException(e);
1019                    }
1020    
1021                    _headerElement = _rootElement.element("header");
1022    
1023                    _layoutsElement = portletDataContext.getImportDataGroupElement(
1024                            Layout.class);
1025    
1026                    _layoutElements = _layoutsElement.elements();
1027            }
1028    
1029            protected void validateFile(PortletDataContext portletDataContext)
1030                    throws Exception {
1031    
1032                    // Build compatibility
1033    
1034                    readXML(portletDataContext);
1035    
1036                    int buildNumber = ReleaseInfo.getBuildNumber();
1037    
1038                    int importBuildNumber = GetterUtil.getInteger(
1039                            _headerElement.attributeValue("build-number"));
1040    
1041                    if (buildNumber != importBuildNumber) {
1042                            throw new LayoutImportException(
1043                                    "LAR build number " + importBuildNumber + " does not match " +
1044                                            "portal build number " + buildNumber);
1045                    }
1046    
1047                    // Type
1048    
1049                    String larType = _headerElement.attributeValue("type");
1050    
1051                    if (!larType.equals("layout-prototype") &&
1052                            !larType.equals("layout-set") &&
1053                            !larType.equals("layout-set-prototype")) {
1054    
1055                            throw new LARTypeException(larType);
1056                    }
1057    
1058                    // Available locales
1059    
1060                    Locale[] sourceAvailableLocales = LocaleUtil.fromLanguageIds(
1061                            StringUtil.split(
1062                                    _headerElement.attributeValue("available-locales")));
1063    
1064                    Locale[] targetAvailableLocales = LanguageUtil.getAvailableLocales(
1065                            portletDataContext.getScopeGroupId());
1066    
1067                    for (Locale sourceAvailableLocale : sourceAvailableLocales) {
1068                            if (!ArrayUtil.contains(
1069                                            targetAvailableLocales, sourceAvailableLocale)) {
1070    
1071                                    LocaleException le = new LocaleException(
1072                                            LocaleException.TYPE_EXPORT_IMPORT);
1073    
1074                                    le.setSourceAvailableLocales(sourceAvailableLocales);
1075                                    le.setTargetAvailableLocales(targetAvailableLocales);
1076    
1077                                    throw le;
1078                            }
1079                    }
1080    
1081                    // Layout prototypes validity
1082    
1083                    validateLayoutPrototypes(
1084                            portletDataContext.getCompanyId(), _layoutsElement,
1085                            _layoutElements);
1086            }
1087    
1088            protected void validateLayoutPrototypes(
1089                            long companyId, Element layoutsElement,
1090                            List<Element> layoutElements)
1091                    throws Exception {
1092    
1093                    List<Tuple> missingLayoutPrototypes = new ArrayList<Tuple>();
1094    
1095                    String layoutSetPrototypeUuid = layoutsElement.attributeValue(
1096                            "layout-set-prototype-uuid");
1097    
1098                    if (Validator.isNotNull(layoutSetPrototypeUuid)) {
1099                            try {
1100                                    LayoutSetPrototypeLocalServiceUtil.
1101                                            getLayoutSetPrototypeByUuidAndCompanyId(
1102                                                    layoutSetPrototypeUuid, companyId);
1103                            }
1104                            catch (NoSuchLayoutSetPrototypeException nlspe) {
1105                                    String layoutSetPrototypeName = layoutsElement.attributeValue(
1106                                            "layout-set-prototype-name");
1107    
1108                                    missingLayoutPrototypes.add(
1109                                            new Tuple(
1110                                                    LayoutSetPrototype.class.getName(),
1111                                                    layoutSetPrototypeUuid, layoutSetPrototypeName));
1112                            }
1113                    }
1114    
1115                    for (Element layoutElement : layoutElements) {
1116                            String action = layoutElement.attributeValue("action");
1117    
1118                            if (action.equals(Constants.SKIP)) {
1119                                    continue;
1120                            }
1121    
1122                            String layoutPrototypeUuid = GetterUtil.getString(
1123                                    layoutElement.attributeValue("layout-prototype-uuid"));
1124    
1125                            if (Validator.isNotNull(layoutPrototypeUuid)) {
1126                                    try {
1127                                            LayoutPrototypeLocalServiceUtil.
1128                                                    getLayoutPrototypeByUuidAndCompanyId(
1129                                                            layoutPrototypeUuid, companyId);
1130                                    }
1131                                    catch (NoSuchLayoutPrototypeException nslpe) {
1132                                            String layoutPrototypeName = GetterUtil.getString(
1133                                                    layoutElement.attributeValue("layout-prototype-name"));
1134    
1135                                            missingLayoutPrototypes.add(
1136                                                    new Tuple(
1137                                                            LayoutPrototype.class.getName(),
1138                                                            layoutPrototypeUuid, layoutPrototypeName));
1139                                    }
1140                            }
1141                    }
1142    
1143                    if (!missingLayoutPrototypes.isEmpty()) {
1144                            throw new LayoutPrototypeException(missingLayoutPrototypes);
1145                    }
1146            }
1147    
1148            private static Log _log = LogFactoryUtil.getLog(LayoutImporter.class);
1149    
1150            private static MethodHandler _loadThemesMethodHandler = new MethodHandler(
1151                    new MethodKey(ThemeLoaderFactory.class, "loadThemes"));
1152    
1153            private DeletionSystemEventImporter _deletionSystemEventImporter =
1154                    new DeletionSystemEventImporter();
1155            private Element _headerElement;
1156            private List<Element> _layoutElements;
1157            private Element _layoutsElement;
1158            private PermissionImporter _permissionImporter = new PermissionImporter();
1159            private PortletImporter _portletImporter = new PortletImporter();
1160            private Element _rootElement;
1161    
1162    }