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                    ServiceContext serviceContext =
245                            ServiceContextThreadLocal.getServiceContext();
246    
247                    if (serviceContext == null) {
248                            serviceContext = new ServiceContext();
249    
250                            serviceContext.setCompanyId(companyId);
251                            serviceContext.setSignedIn(false);
252                            serviceContext.setUserId(userId);
253    
254                            ServiceContextThreadLocal.pushServiceContext(serviceContext);
255                    }
256    
257                    UserIdStrategy strategy = _portletImporter.getUserIdStrategy(
258                            user, userIdStrategy);
259    
260                    if (BackgroundTaskThreadLocal.hasBackgroundTask()) {
261                            ManifestSummary manifestSummary =
262                                    ExportImportHelperUtil.getManifestSummary(
263                                            userId, groupId, parameterMap, file);
264    
265                            PortletDataHandlerStatusMessageSenderUtil.sendStatusMessage(
266                                    "layout", manifestSummary);
267                    }
268    
269                    ZipReader zipReader = ZipReaderFactoryUtil.getZipReader(file);
270    
271                    PortletDataContext portletDataContext =
272                            PortletDataContextFactoryUtil.createImportPortletDataContext(
273                                    companyId, groupId, parameterMap, strategy, zipReader);
274    
275                    portletDataContext.setPortetDataContextListener(
276                            new PortletDataContextListenerImpl(portletDataContext));
277    
278                    portletDataContext.setPrivateLayout(privateLayout);
279    
280                    // Zip
281    
282                    validateFile(portletDataContext);
283    
284                    // Company id
285    
286                    long sourceCompanyId = GetterUtil.getLong(
287                            _headerElement.attributeValue("company-id"));
288    
289                    portletDataContext.setSourceCompanyId(sourceCompanyId);
290    
291                    // Company group id
292    
293                    long sourceCompanyGroupId = GetterUtil.getLong(
294                            _headerElement.attributeValue("company-group-id"));
295    
296                    portletDataContext.setSourceCompanyGroupId(sourceCompanyGroupId);
297    
298                    // Group id
299    
300                    long sourceGroupId = GetterUtil.getLong(
301                            _headerElement.attributeValue("group-id"));
302    
303                    portletDataContext.setSourceGroupId(sourceGroupId);
304    
305                    // User personal site group id
306    
307                    long sourceUserPersonalSiteGroupId = GetterUtil.getLong(
308                            _headerElement.attributeValue("user-personal-site-group-id"));
309    
310                    portletDataContext.setSourceUserPersonalSiteGroupId(
311                            sourceUserPersonalSiteGroupId);
312    
313                    // Layout and layout set prototype
314    
315                    String layoutSetPrototypeUuid = _layoutsElement.attributeValue(
316                            "layout-set-prototype-uuid");
317    
318                    String larType = _headerElement.attributeValue("type");
319    
320                    if (group.isLayoutPrototype() && larType.equals("layout-prototype")) {
321                            deleteMissingLayouts = false;
322    
323                            LayoutPrototype layoutPrototype =
324                                    LayoutPrototypeLocalServiceUtil.getLayoutPrototype(
325                                            group.getClassPK());
326    
327                            String layoutPrototypeUuid = GetterUtil.getString(
328                                    _headerElement.attributeValue("type-uuid"));
329    
330                            LayoutPrototype existingLayoutPrototype = null;
331    
332                            if (Validator.isNotNull(layoutPrototypeUuid)) {
333                                    try {
334                                            existingLayoutPrototype =
335                                                    LayoutPrototypeLocalServiceUtil.
336                                                            getLayoutPrototypeByUuidAndCompanyId(
337                                                                    layoutPrototypeUuid, companyId);
338                                    }
339                                    catch (NoSuchLayoutPrototypeException nslpe) {
340                                    }
341                            }
342    
343                            if (existingLayoutPrototype == null) {
344                                    List<Layout> layouts =
345                                            LayoutLocalServiceUtil.getLayoutsByLayoutPrototypeUuid(
346                                                    layoutPrototype.getUuid());
347    
348                                    layoutPrototype.setUuid(layoutPrototypeUuid);
349    
350                                    LayoutPrototypeLocalServiceUtil.updateLayoutPrototype(
351                                            layoutPrototype);
352    
353                                    for (Layout layout : layouts) {
354                                            layout.setLayoutPrototypeUuid(layoutPrototypeUuid);
355    
356                                            LayoutLocalServiceUtil.updateLayout(layout);
357                                    }
358                            }
359                    }
360                    else if (group.isLayoutSetPrototype() &&
361                                     larType.equals("layout-set-prototype")) {
362    
363                            LayoutSetPrototype layoutSetPrototype =
364                                    LayoutSetPrototypeLocalServiceUtil.getLayoutSetPrototype(
365                                            group.getClassPK());
366    
367                            String importedLayoutSetPrototypeUuid = GetterUtil.getString(
368                                    _headerElement.attributeValue("type-uuid"));
369    
370                            LayoutSetPrototype existingLayoutSetPrototype = null;
371    
372                            if (Validator.isNotNull(importedLayoutSetPrototypeUuid)) {
373                                    try {
374                                            existingLayoutSetPrototype =
375                                                    LayoutSetPrototypeLocalServiceUtil.
376                                                            getLayoutSetPrototypeByUuidAndCompanyId(
377                                                                    importedLayoutSetPrototypeUuid, companyId);
378                                    }
379                                    catch (NoSuchLayoutSetPrototypeException nslspe) {
380                                    }
381                            }
382    
383                            if (existingLayoutSetPrototype == null) {
384                                    layoutSetPrototype.setUuid(importedLayoutSetPrototypeUuid);
385    
386                                    LayoutSetPrototypeLocalServiceUtil.updateLayoutSetPrototype(
387                                            layoutSetPrototype);
388                            }
389                    }
390                    else if (larType.equals("layout-set-prototype")) {
391                            layoutSetPrototypeUuid = GetterUtil.getString(
392                                    _headerElement.attributeValue("type-uuid"));
393                    }
394    
395                    if (Validator.isNotNull(layoutSetPrototypeUuid)) {
396                            layoutSet.setLayoutSetPrototypeUuid(layoutSetPrototypeUuid);
397                            layoutSet.setLayoutSetPrototypeLinkEnabled(
398                                    layoutSetPrototypeLinkEnabled);
399    
400                            LayoutSetLocalServiceUtil.updateLayoutSet(layoutSet);
401                    }
402    
403                    // Look and feel
404    
405                    if (importLogo) {
406                            String logoPath = _headerElement.attributeValue("logo-path");
407    
408                            byte[] iconBytes = portletDataContext.getZipEntryAsByteArray(
409                                    logoPath);
410    
411                            if (ArrayUtil.isNotEmpty(iconBytes)) {
412                                    File logo = null;
413    
414                                    try {
415                                            logo = FileUtil.createTempFile(iconBytes);
416    
417                                            LayoutSetLocalServiceUtil.updateLogo(
418                                                    groupId, privateLayout, true, logo);
419                                    }
420                                    finally {
421                                            FileUtil.delete(logo);
422                                    }
423                            }
424                            else {
425                                    LayoutSetLocalServiceUtil.updateLogo(
426                                            groupId, privateLayout, false, (File)null);
427                            }
428                    }
429    
430                    _themeImporter.importTheme(portletDataContext, layoutSet);
431    
432                    if (importLayoutSetSettings) {
433                            String settings = GetterUtil.getString(
434                                    _headerElement.elementText("settings"));
435    
436                            LayoutSetLocalServiceUtil.updateSettings(
437                                    groupId, privateLayout, settings);
438                    }
439    
440                    // Read asset categories, asset tags, comments, locks, permissions, and
441                    // ratings entries to make them available to the data handlers through
442                    // the context
443    
444                    if (importPermissions) {
445                            _permissionImporter.readPortletDataPermissions(portletDataContext);
446                    }
447    
448                    _portletImporter.readAssetCategories(portletDataContext);
449                    _portletImporter.readAssetTags(portletDataContext);
450                    _portletImporter.readComments(portletDataContext);
451                    _portletImporter.readExpandoTables(portletDataContext);
452                    _portletImporter.readLocks(portletDataContext);
453                    _portletImporter.readRatingsEntries(portletDataContext);
454    
455                    // Layouts
456    
457                    List<Layout> previousLayouts = LayoutUtil.findByG_P(
458                            groupId, privateLayout);
459    
460                    // Remove layouts that were deleted from the layout set prototype
461    
462                    if (Validator.isNotNull(layoutSetPrototypeUuid) &&
463                            layoutSetPrototypeLinkEnabled) {
464    
465                            LayoutSetPrototype layoutSetPrototype =
466                                    LayoutSetPrototypeLocalServiceUtil.
467                                            getLayoutSetPrototypeByUuidAndCompanyId(
468                                                    layoutSetPrototypeUuid, companyId);
469    
470                            for (Layout layout : previousLayouts) {
471                                    String sourcePrototypeLayoutUuid =
472                                            layout.getSourcePrototypeLayoutUuid();
473    
474                                    if (Validator.isNull(layout.getSourcePrototypeLayoutUuid())) {
475                                            continue;
476                                    }
477    
478                                    Layout sourcePrototypeLayout = LayoutUtil.fetchByUUID_G_P(
479                                            sourcePrototypeLayoutUuid, layoutSetPrototype.getGroupId(),
480                                            true);
481    
482                                    if (sourcePrototypeLayout == null) {
483                                            LayoutLocalServiceUtil.deleteLayout(
484                                                    layout, false, serviceContext);
485                                    }
486                            }
487                    }
488    
489                    List<String> sourceLayoutsUuids = new ArrayList<String>();
490                    List<Layout> newLayouts = new ArrayList<Layout>();
491    
492                    if (_log.isDebugEnabled()) {
493                            if (_layoutElements.size() > 0) {
494                                    _log.debug("Importing layouts");
495                            }
496                    }
497    
498                    for (Element layoutElement : _layoutElements) {
499                            importLayout(
500                                    portletDataContext, sourceLayoutsUuids, newLayouts,
501                                    layoutElement);
502                    }
503    
504                    Element portletsElement = _rootElement.element("portlets");
505    
506                    List<Element> portletElements = portletsElement.elements("portlet");
507    
508                    // Delete portlet data
509    
510                    Map<Long, Layout> newLayoutsMap =
511                            (Map<Long, Layout>)portletDataContext.getNewPrimaryKeysMap(
512                                    Layout.class + ".layout");
513    
514                    if (deletePortletData) {
515                            if (_log.isDebugEnabled()) {
516                                    if (portletElements.size() > 0) {
517                                            _log.debug("Deleting portlet data");
518                                    }
519                            }
520    
521                            for (Element portletElement : portletElements) {
522                                    String portletId = portletElement.attributeValue("portlet-id");
523                                    long layoutId = GetterUtil.getLong(
524                                            portletElement.attributeValue("layout-id"));
525    
526                                    Layout layout = newLayoutsMap.get(layoutId);
527    
528                                    long plid = layout.getPlid();
529    
530                                    portletDataContext.setPlid(plid);
531    
532                                    _portletImporter.deletePortletData(
533                                            portletDataContext, portletId, plid);
534                            }
535                    }
536    
537                    // Import portlets
538    
539                    if (_log.isDebugEnabled()) {
540                            if (portletElements.size() > 0) {
541                                    _log.debug("Importing portlets");
542                            }
543                    }
544    
545                    for (Element portletElement : portletElements) {
546                            String portletPath = portletElement.attributeValue("path");
547                            String portletId = portletElement.attributeValue("portlet-id");
548                            long layoutId = GetterUtil.getLong(
549                                    portletElement.attributeValue("layout-id"));
550                            long oldPlid = GetterUtil.getLong(
551                                    portletElement.attributeValue("old-plid"));
552    
553                            Portlet portlet = PortletLocalServiceUtil.getPortletById(
554                                    portletDataContext.getCompanyId(), portletId);
555    
556                            if (!portlet.isActive() || portlet.isUndeployedPortlet()) {
557                                    continue;
558                            }
559    
560                            Layout layout = newLayoutsMap.get(layoutId);
561    
562                            long plid = LayoutConstants.DEFAULT_PLID;
563    
564                            if (layout != null) {
565                                    plid = layout.getPlid();
566                            }
567    
568                            portletDataContext.setPlid(plid);
569                            portletDataContext.setOldPlid(oldPlid);
570    
571                            Document portletDocument = SAXReaderUtil.read(
572                                    portletDataContext.getZipEntryAsString(portletPath));
573    
574                            portletElement = portletDocument.getRootElement();
575    
576                            // The order of the import is important. You must always import the
577                            // portlet preferences first, then the portlet data, then the
578                            // portlet permissions. The import of the portlet data assumes that
579                            // portlet preferences already exist.
580    
581                            _portletImporter.setPortletScope(
582                                    portletDataContext, portletElement);
583    
584                            long portletPreferencesGroupId = groupId;
585    
586                            Element portletDataElement = portletElement.element("portlet-data");
587    
588                            boolean[] importPortletControls = getImportPortletControls(
589                                    companyId, portletId, parameterMap, portletDataElement);
590    
591                            try {
592                                    if (layout != null) {
593                                            portletPreferencesGroupId = layout.getGroupId();
594                                    }
595    
596                                    // Portlet preferences
597    
598                                    _portletImporter.importPortletPreferences(
599                                            portletDataContext, layoutSet.getCompanyId(),
600                                            portletPreferencesGroupId, layout, null, portletElement,
601                                            importPortletControls[2], importPortletControls[0],
602                                            importPortletControls[3], false, importPortletControls[1]);
603    
604                                    // Portlet data
605    
606                                    if (importPortletControls[1]) {
607                                            _portletImporter.importPortletData(
608                                                    portletDataContext, portletId, plid,
609                                                    portletDataElement);
610                                    }
611                            }
612                            finally {
613                                    _portletImporter.resetPortletScope(
614                                            portletDataContext, portletPreferencesGroupId);
615                            }
616    
617                            // Portlet permissions
618    
619                            if (importPermissions) {
620                                    _permissionImporter.importPortletPermissions(
621                                            layoutCache, companyId, groupId, userId, layout,
622                                            portletElement, portletId);
623                            }
624    
625                            // Archived setups
626    
627                            _portletImporter.importPortletPreferences(
628                                    portletDataContext, layoutSet.getCompanyId(), groupId, null,
629                                    null, portletElement, importPortletControls[2],
630                                    importPortletControls[0], importPortletControls[3], false,
631                                    importPortletControls[1]);
632                    }
633    
634                    if (importPermissions) {
635                            if (userId > 0) {
636                                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
637                                            User.class);
638    
639                                    indexer.reindex(userId);
640                            }
641                    }
642    
643                    // Asset links
644    
645                    _portletImporter.readAssetLinks(portletDataContext);
646    
647                    // Delete missing layouts
648    
649                    if (deleteMissingLayouts) {
650                            deleteMissingLayouts(
651                                    sourceLayoutsUuids, previousLayouts, serviceContext);
652                    }
653    
654                    // Page count
655    
656                    layoutSet = LayoutSetLocalServiceUtil.updatePageCount(
657                            groupId, privateLayout);
658    
659                    // Site
660    
661                    GroupLocalServiceUtil.updateSite(groupId, true);
662    
663                    // Last merge time must be the same for merged layouts and the layout
664                    // set
665    
666                    long lastMergeTime = System.currentTimeMillis();
667    
668                    for (Layout layout : newLayouts) {
669                            boolean modifiedTypeSettingsProperties = false;
670    
671                            UnicodeProperties typeSettingsProperties =
672                                    layout.getTypeSettingsProperties();
673    
674                            // Journal article layout type
675    
676                            String articleId = typeSettingsProperties.getProperty("article-id");
677    
678                            if (Validator.isNotNull(articleId)) {
679                                    Map<String, String> articleIds =
680                                            (Map<String, String>)portletDataContext.
681                                                    getNewPrimaryKeysMap(
682                                                            JournalArticle.class + ".articleId");
683    
684                                    typeSettingsProperties.setProperty(
685                                            "article-id",
686                                            MapUtil.getString(articleIds, articleId, articleId));
687    
688                                    modifiedTypeSettingsProperties = true;
689                            }
690    
691                            // Last merge time for layout
692    
693                            if (layoutsImportMode.equals(
694                                            PortletDataHandlerKeys.
695                                                    LAYOUTS_IMPORT_MODE_CREATED_FROM_PROTOTYPE)) {
696    
697                                    typeSettingsProperties.setProperty(
698                                            Sites.LAST_MERGE_TIME, String.valueOf(lastMergeTime));
699    
700                                    modifiedTypeSettingsProperties = true;
701                            }
702    
703                            if (modifiedTypeSettingsProperties) {
704                                    LayoutUtil.update(layout);
705                            }
706                    }
707    
708                    // Last merge time for layout set
709    
710                    if (layoutsImportMode.equals(
711                                    PortletDataHandlerKeys.
712                                            LAYOUTS_IMPORT_MODE_CREATED_FROM_PROTOTYPE)) {
713    
714                            UnicodeProperties settingsProperties =
715                                    layoutSet.getSettingsProperties();
716    
717                            String mergeFailFriendlyURLLayouts =
718                                    settingsProperties.getProperty(
719                                            Sites.MERGE_FAIL_FRIENDLY_URL_LAYOUTS);
720    
721                            if (Validator.isNull(mergeFailFriendlyURLLayouts)) {
722                                    settingsProperties.setProperty(
723                                            Sites.LAST_MERGE_TIME, String.valueOf(lastMergeTime));
724    
725                                    LayoutSetLocalServiceUtil.updateLayoutSet(layoutSet);
726                            }
727                    }
728    
729                    // Deletion system events
730    
731                    _deletionSystemEventImporter.importDeletionSystemEvents(
732                            portletDataContext);
733    
734                    if (_log.isInfoEnabled()) {
735                            _log.info("Importing layouts takes " + stopWatch.getTime() + " ms");
736                    }
737    
738                    zipReader.close();
739            }
740    
741            protected boolean[] getImportPortletControls(
742                            long companyId, String portletId,
743                            Map<String, String[]> parameterMap, Element portletDataElement)
744                    throws Exception {
745    
746                    boolean importPortletConfiguration = MapUtil.getBoolean(
747                            parameterMap, PortletDataHandlerKeys.PORTLET_CONFIGURATION);
748                    boolean importPortletConfigurationAll = MapUtil.getBoolean(
749                            parameterMap, PortletDataHandlerKeys.PORTLET_CONFIGURATION_ALL);
750                    boolean importPortletData = MapUtil.getBoolean(
751                            parameterMap, PortletDataHandlerKeys.PORTLET_DATA);
752                    boolean importPortletDataAll = MapUtil.getBoolean(
753                            parameterMap, PortletDataHandlerKeys.PORTLET_DATA_ALL);
754    
755                    if (_log.isDebugEnabled()) {
756                            _log.debug("Import portlet data " + importPortletData);
757                            _log.debug("Import all portlet data " + importPortletDataAll);
758                            _log.debug(
759                                    "Import portlet configuration " + importPortletConfiguration);
760                    }
761    
762                    boolean importCurPortletData = importPortletData;
763    
764                    String rootPortletId =
765                            ExportImportHelperUtil.getExportableRootPortletId(
766                                    companyId, portletId);
767    
768                    if (portletDataElement == null) {
769                            importCurPortletData = false;
770                    }
771                    else if (importPortletDataAll) {
772                            importCurPortletData = true;
773                    }
774                    else if (rootPortletId != null) {
775                            importCurPortletData =
776                                    importPortletData &&
777                                    MapUtil.getBoolean(
778                                            parameterMap,
779                                            PortletDataHandlerKeys.PORTLET_DATA +
780                                                    StringPool.UNDERLINE + rootPortletId);
781                    }
782    
783                    boolean importCurPortletArchivedSetups = importPortletConfiguration;
784                    boolean importCurPortletSetup = importPortletConfiguration;
785                    boolean importCurPortletUserPreferences = importPortletConfiguration;
786    
787                    if (importPortletConfigurationAll) {
788                            importCurPortletArchivedSetups =
789                                    MapUtil.getBoolean(
790                                            parameterMap,
791                                            PortletDataHandlerKeys.PORTLET_ARCHIVED_SETUPS_ALL);
792                            importCurPortletSetup =
793                                    MapUtil.getBoolean(
794                                            parameterMap, PortletDataHandlerKeys.PORTLET_SETUP_ALL);
795                            importCurPortletUserPreferences =
796                                    MapUtil.getBoolean(
797                                            parameterMap,
798                                            PortletDataHandlerKeys.PORTLET_USER_PREFERENCES_ALL);
799                    }
800                    else if (rootPortletId != null) {
801                            boolean importCurPortletConfiguration =
802                                    importPortletConfiguration &&
803                                    MapUtil.getBoolean(
804                                            parameterMap,
805                                            PortletDataHandlerKeys.PORTLET_CONFIGURATION +
806                                                    StringPool.UNDERLINE + rootPortletId);
807    
808                            importCurPortletArchivedSetups =
809                                    importCurPortletConfiguration &&
810                                    MapUtil.getBoolean(
811                                            parameterMap,
812                                            PortletDataHandlerKeys.PORTLET_ARCHIVED_SETUPS +
813                                                    StringPool.UNDERLINE + rootPortletId);
814                            importCurPortletSetup =
815                                    importCurPortletConfiguration &&
816                                    MapUtil.getBoolean(
817                                            parameterMap,
818                                            PortletDataHandlerKeys.PORTLET_SETUP +
819                                                    StringPool.UNDERLINE + rootPortletId);
820                            importCurPortletUserPreferences =
821                                    importCurPortletConfiguration &&
822                                    MapUtil.getBoolean(
823                                            parameterMap,
824                                            PortletDataHandlerKeys.PORTLET_USER_PREFERENCES +
825                                                    StringPool.UNDERLINE + rootPortletId);
826                    }
827    
828                    return new boolean[] {
829                            importCurPortletArchivedSetups, importCurPortletData,
830                            importCurPortletSetup, importCurPortletUserPreferences};
831            }
832    
833            protected void importLayout(
834                            PortletDataContext portletDataContext,
835                            List<String> sourceLayoutsUuids, List<Layout> newLayouts,
836                            Element layoutElement)
837                    throws Exception {
838    
839                    String action = layoutElement.attributeValue("action");
840    
841                    if (!action.equals(Constants.SKIP)) {
842                            StagedModelDataHandlerUtil.importStagedModel(
843                                    portletDataContext, layoutElement);
844    
845                            List<Layout> portletDataContextNewLayouts =
846                                    portletDataContext.getNewLayouts();
847    
848                            newLayouts.addAll(portletDataContextNewLayouts);
849    
850                            portletDataContextNewLayouts.clear();
851                    }
852    
853                    if (!action.equals(Constants.DELETE)) {
854                            sourceLayoutsUuids.add(layoutElement.attributeValue("uuid"));
855                    }
856            }
857    
858            protected void readXML(PortletDataContext portletDataContext)
859                    throws Exception {
860    
861                    if ((_rootElement != null) && (_headerElement != null) &&
862                            (_layoutsElement != null) && (_layoutElements != null)) {
863    
864                            return;
865                    }
866    
867                    String xml = portletDataContext.getZipEntryAsString("/manifest.xml");
868    
869                    if (xml == null) {
870                            throw new LARFileException("manifest.xml not found in the LAR");
871                    }
872    
873                    try {
874                            Document document = SAXReaderUtil.read(xml);
875    
876                            _rootElement = document.getRootElement();
877    
878                            portletDataContext.setImportDataRootElement(_rootElement);
879                    }
880                    catch (Exception e) {
881                            throw new LARFileException(e);
882                    }
883    
884                    _headerElement = _rootElement.element("header");
885    
886                    _layoutsElement = portletDataContext.getImportDataGroupElement(
887                            Layout.class);
888    
889                    _layoutElements = _layoutsElement.elements();
890            }
891    
892            protected void validateFile(PortletDataContext portletDataContext)
893                    throws Exception {
894    
895                    // Build compatibility
896    
897                    readXML(portletDataContext);
898    
899                    int buildNumber = ReleaseInfo.getBuildNumber();
900    
901                    int importBuildNumber = GetterUtil.getInteger(
902                            _headerElement.attributeValue("build-number"));
903    
904                    if (buildNumber != importBuildNumber) {
905                            throw new LayoutImportException(
906                                    "LAR build number " + importBuildNumber + " does not match " +
907                                            "portal build number " + buildNumber);
908                    }
909    
910                    // Type
911    
912                    String larType = _headerElement.attributeValue("type");
913    
914                    if (!larType.equals("layout-prototype") &&
915                            !larType.equals("layout-set") &&
916                            !larType.equals("layout-set-prototype")) {
917    
918                            throw new LARTypeException(larType);
919                    }
920    
921                    // Available locales
922    
923                    Locale[] sourceAvailableLocales = LocaleUtil.fromLanguageIds(
924                            StringUtil.split(
925                                    _headerElement.attributeValue("available-locales")));
926    
927                    Locale[] targetAvailableLocales = LanguageUtil.getAvailableLocales(
928                            portletDataContext.getScopeGroupId());
929    
930                    for (Locale sourceAvailableLocale : sourceAvailableLocales) {
931                            if (!ArrayUtil.contains(
932                                            targetAvailableLocales, sourceAvailableLocale)) {
933    
934                                    LocaleException le = new LocaleException(
935                                            LocaleException.TYPE_EXPORT_IMPORT);
936    
937                                    le.setSourceAvailableLocales(sourceAvailableLocales);
938                                    le.setTargetAvailableLocales(targetAvailableLocales);
939    
940                                    throw le;
941                            }
942                    }
943    
944                    // Layout prototypes validity
945    
946                    validateLayoutPrototypes(
947                            portletDataContext.getCompanyId(), _layoutsElement,
948                            _layoutElements);
949            }
950    
951            protected void validateLayoutPrototypes(
952                            long companyId, Element layoutsElement,
953                            List<Element> layoutElements)
954                    throws Exception {
955    
956                    List<Tuple> missingLayoutPrototypes = new ArrayList<Tuple>();
957    
958                    String layoutSetPrototypeUuid = layoutsElement.attributeValue(
959                            "layout-set-prototype-uuid");
960    
961                    if (Validator.isNotNull(layoutSetPrototypeUuid)) {
962                            try {
963                                    LayoutSetPrototypeLocalServiceUtil.
964                                            getLayoutSetPrototypeByUuidAndCompanyId(
965                                                    layoutSetPrototypeUuid, companyId);
966                            }
967                            catch (NoSuchLayoutSetPrototypeException nlspe) {
968                                    String layoutSetPrototypeName = layoutsElement.attributeValue(
969                                            "layout-set-prototype-name");
970    
971                                    missingLayoutPrototypes.add(
972                                            new Tuple(
973                                                    LayoutSetPrototype.class.getName(),
974                                                    layoutSetPrototypeUuid, layoutSetPrototypeName));
975                            }
976                    }
977    
978                    for (Element layoutElement : layoutElements) {
979                            String action = layoutElement.attributeValue("action");
980    
981                            if (action.equals(Constants.SKIP)) {
982                                    continue;
983                            }
984    
985                            String layoutPrototypeUuid = GetterUtil.getString(
986                                    layoutElement.attributeValue("layout-prototype-uuid"));
987    
988                            if (Validator.isNotNull(layoutPrototypeUuid)) {
989                                    try {
990                                            LayoutPrototypeLocalServiceUtil.
991                                                    getLayoutPrototypeByUuidAndCompanyId(
992                                                            layoutPrototypeUuid, companyId);
993                                    }
994                                    catch (NoSuchLayoutPrototypeException nslpe) {
995                                            String layoutPrototypeName = GetterUtil.getString(
996                                                    layoutElement.attributeValue("layout-prototype-name"));
997    
998                                            missingLayoutPrototypes.add(
999                                                    new Tuple(
1000                                                            LayoutPrototype.class.getName(),
1001                                                            layoutPrototypeUuid, layoutPrototypeName));
1002                                    }
1003                            }
1004                    }
1005    
1006                    if (!missingLayoutPrototypes.isEmpty()) {
1007                            throw new LayoutPrototypeException(missingLayoutPrototypes);
1008                    }
1009            }
1010    
1011            private static Log _log = LogFactoryUtil.getLog(LayoutImporter.class);
1012    
1013            private DeletionSystemEventImporter _deletionSystemEventImporter =
1014                    new DeletionSystemEventImporter();
1015            private Element _headerElement;
1016            private List<Element> _layoutElements;
1017            private Element _layoutsElement;
1018            private PermissionImporter _permissionImporter = new PermissionImporter();
1019            private PortletImporter _portletImporter = new PortletImporter();
1020            private Element _rootElement;
1021            private ThemeImporter _themeImporter = new ThemeImporter();
1022    
1023    }