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