/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. */ package com.liferay.exportimport.controller; import static com.liferay.exportimport.kernel.lifecycle.ExportImportLifecycleConstants.EVENT_LAYOUT_IMPORT_FAILED; import static com.liferay.exportimport.kernel.lifecycle.ExportImportLifecycleConstants.EVENT_LAYOUT_IMPORT_STARTED; import static com.liferay.exportimport.kernel.lifecycle.ExportImportLifecycleConstants.EVENT_LAYOUT_IMPORT_SUCCEEDED; import static com.liferay.exportimport.kernel.lifecycle.ExportImportLifecycleConstants.PROCESS_FLAG_LAYOUT_IMPORT_IN_PROCESS; import static com.liferay.exportimport.kernel.lifecycle.ExportImportLifecycleConstants.PROCESS_FLAG_LAYOUT_STAGING_IN_PROCESS; import aQute.bnd.annotation.ProviderType; import com.liferay.exportimport.constants.ExportImportConstants; import com.liferay.exportimport.kernel.controller.ExportImportController; import com.liferay.exportimport.kernel.controller.ImportController; import com.liferay.exportimport.kernel.exception.LARFileException; import com.liferay.exportimport.kernel.exception.LARTypeException; import com.liferay.exportimport.kernel.exception.LayoutImportException; import com.liferay.exportimport.kernel.exception.MissingReferenceException; import com.liferay.exportimport.kernel.lar.ExportImportHelperUtil; import com.liferay.exportimport.kernel.lar.ExportImportThreadLocal; import com.liferay.exportimport.kernel.lar.ManifestSummary; import com.liferay.exportimport.kernel.lar.MissingReference; import com.liferay.exportimport.kernel.lar.MissingReferences; import com.liferay.exportimport.kernel.lar.PortletDataContext; import com.liferay.exportimport.kernel.lar.PortletDataContextFactoryUtil; import com.liferay.exportimport.kernel.lar.PortletDataHandler; import com.liferay.exportimport.kernel.lar.PortletDataHandlerKeys; import com.liferay.exportimport.kernel.lar.StagedModelDataHandlerUtil; import com.liferay.exportimport.kernel.lar.StagedModelType; import com.liferay.exportimport.kernel.lar.UserIdStrategy; import com.liferay.exportimport.kernel.lifecycle.ExportImportLifecycleManager; import com.liferay.exportimport.kernel.model.ExportImportConfiguration; import com.liferay.exportimport.lar.DeletionSystemEventImporter; import com.liferay.exportimport.lar.LayoutCache; import com.liferay.exportimport.lar.PermissionImporter; import com.liferay.exportimport.portlet.data.handler.provider.PortletDataHandlerProvider; import com.liferay.portal.kernel.exception.LayoutPrototypeException; import com.liferay.portal.kernel.exception.LocaleException; import com.liferay.portal.kernel.exception.NoSuchLayoutPrototypeException; import com.liferay.portal.kernel.exception.NoSuchLayoutSetPrototypeException; import com.liferay.portal.kernel.exception.PortalException; import com.liferay.portal.kernel.language.LanguageUtil; import com.liferay.portal.kernel.log.Log; import com.liferay.portal.kernel.log.LogFactoryUtil; import com.liferay.portal.kernel.model.Group; import com.liferay.portal.kernel.model.Layout; import com.liferay.portal.kernel.model.LayoutConstants; import com.liferay.portal.kernel.model.LayoutPrototype; import com.liferay.portal.kernel.model.LayoutSet; import com.liferay.portal.kernel.model.LayoutSetPrototype; import com.liferay.portal.kernel.model.Portlet; import com.liferay.portal.kernel.plugin.Version; import com.liferay.portal.kernel.service.GroupLocalService; import com.liferay.portal.kernel.service.LayoutLocalService; import com.liferay.portal.kernel.service.LayoutPrototypeLocalService; import com.liferay.portal.kernel.service.LayoutSetLocalService; import com.liferay.portal.kernel.service.LayoutSetPrototypeLocalService; import com.liferay.portal.kernel.service.PortletLocalService; import com.liferay.portal.kernel.service.ServiceContext; import com.liferay.portal.kernel.service.ServiceContextThreadLocal; import com.liferay.portal.kernel.util.Constants; import com.liferay.portal.kernel.util.GetterUtil; import com.liferay.portal.kernel.util.LocaleUtil; import com.liferay.portal.kernel.util.MapUtil; import com.liferay.portal.kernel.util.ReleaseInfo; import com.liferay.portal.kernel.util.StringUtil; import com.liferay.portal.kernel.util.Tuple; import com.liferay.portal.kernel.util.Validator; import com.liferay.portal.kernel.xml.Document; import com.liferay.portal.kernel.xml.Element; import com.liferay.portal.kernel.xml.Node; import com.liferay.portal.kernel.xml.SAXReaderUtil; import com.liferay.portal.kernel.xml.XPath; import com.liferay.portal.kernel.zip.ZipReader; import com.liferay.portal.kernel.zip.ZipReaderFactoryUtil; import com.liferay.site.model.adapter.StagedGroup; import java.io.File; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.function.BiPredicate; import java.util.stream.Stream; import org.apache.commons.lang.time.StopWatch; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; /** * @author Brian Wing Shun Chan * @author Joel Kozikowski * @author Charles May * @author Raymond Augé * @author Jorge Ferrer * @author Bruno Farache * @author Wesley Gong * @author Zsigmond Rab * @author Douglas Wong * @author Julio Camarero * @author Zsolt Berentey */ @Component( immediate = true, property = {"model.class.name=com.liferay.portal.kernel.model.Layout"}, service = {ExportImportController.class, LayoutImportController.class} ) @ProviderType public class LayoutImportController implements ImportController { @Override public void importDataDeletions( ExportImportConfiguration exportImportConfiguration, File file) throws Exception { ZipReader zipReader = null; try { // LAR validation ExportImportThreadLocal.setLayoutDataDeletionImportInProcess(true); Map<String, Serializable> settingsMap = exportImportConfiguration.getSettingsMap(); long targetGroupId = MapUtil.getLong(settingsMap, "targetGroupId"); boolean privateLayout = MapUtil.getBoolean( settingsMap, "privateLayout"); Map<String, String[]> parameterMap = (Map<String, String[]>)settingsMap.get("parameterMap"); LayoutSet layoutSet = _layoutSetLocalService.getLayoutSet( targetGroupId, privateLayout); zipReader = ZipReaderFactoryUtil.getZipReader(file); validateFile( layoutSet.getCompanyId(), targetGroupId, parameterMap, zipReader); PortletDataContext portletDataContext = getPortletDataContext( exportImportConfiguration, file); boolean deletePortletData = MapUtil.getBoolean( parameterMap, PortletDataHandlerKeys.DELETE_PORTLET_DATA); // Portlet data deletion if (deletePortletData) { if (_log.isDebugEnabled()) { _log.debug("Deleting portlet data"); } deletePortletData(portletDataContext); } // Deletion system events populateDeletionStagedModelTypes(portletDataContext); _deletionSystemEventImporter.importDeletionSystemEvents( portletDataContext); } finally { ExportImportThreadLocal.setLayoutDataDeletionImportInProcess(false); if (zipReader != null) { zipReader.close(); } } } @Override public void importFile( ExportImportConfiguration exportImportConfiguration, File file) throws Exception { PortletDataContext portletDataContext = null; try { ExportImportThreadLocal.setLayoutImportInProcess(true); portletDataContext = getPortletDataContext( exportImportConfiguration, file); _exportImportLifecycleManager.fireExportImportLifecycleEvent( EVENT_LAYOUT_IMPORT_STARTED, getProcessFlag(), String.valueOf( exportImportConfiguration.getExportImportConfigurationId()), PortletDataContextFactoryUtil.clonePortletDataContext( portletDataContext)); Map<String, Serializable> settingsMap = exportImportConfiguration.getSettingsMap(); long userId = MapUtil.getLong(settingsMap, "userId"); doImportFile(portletDataContext, userId); ExportImportThreadLocal.setLayoutImportInProcess(false); _exportImportLifecycleManager.fireExportImportLifecycleEvent( EVENT_LAYOUT_IMPORT_SUCCEEDED, getProcessFlag(), String.valueOf( exportImportConfiguration.getExportImportConfigurationId()), PortletDataContextFactoryUtil.clonePortletDataContext( portletDataContext), userId); } catch (Throwable t) { ExportImportThreadLocal.setLayoutImportInProcess(false); _exportImportLifecycleManager.fireExportImportLifecycleEvent( EVENT_LAYOUT_IMPORT_FAILED, getProcessFlag(), String.valueOf( exportImportConfiguration.getExportImportConfigurationId()), PortletDataContextFactoryUtil.clonePortletDataContext( portletDataContext), t); throw t; } } @Override public MissingReferences validateFile( ExportImportConfiguration exportImportConfiguration, File file) throws Exception { ZipReader zipReader = null; try { ExportImportThreadLocal.setLayoutValidationInProcess(true); Map<String, Serializable> settingsMap = exportImportConfiguration.getSettingsMap(); long targetGroupId = MapUtil.getLong(settingsMap, "targetGroupId"); boolean privateLayout = MapUtil.getBoolean( settingsMap, "privateLayout"); Map<String, String[]> parameterMap = (Map<String, String[]>)settingsMap.get("parameterMap"); LayoutSet layoutSet = _layoutSetLocalService.getLayoutSet( targetGroupId, privateLayout); zipReader = ZipReaderFactoryUtil.getZipReader(file); validateFile( layoutSet.getCompanyId(), targetGroupId, parameterMap, zipReader); PortletDataContext portletDataContext = getPortletDataContext( exportImportConfiguration, file); portletDataContext.setPrivateLayout(privateLayout); MissingReferences missingReferences = ExportImportHelperUtil.validateMissingReferences( portletDataContext); Map<String, MissingReference> dependencyMissingReferences = missingReferences.getDependencyMissingReferences(); if (!dependencyMissingReferences.isEmpty()) { throw new MissingReferenceException(missingReferences); } return missingReferences; } finally { ExportImportThreadLocal.setLayoutValidationInProcess(false); if (zipReader != null) { zipReader.close(); } } } /** * @deprecated As of 4.0.0 */ @Deprecated protected void deleteMissingLayouts( PortletDataContext portletDataContext, List<String> sourceLayoutUuids, List<Layout> previousLayouts, ServiceContext serviceContext) throws Exception { } protected void deletePortletData(PortletDataContext portletDataContext) throws Exception { List<Element> portletElements = fetchPortletElements( portletDataContext.getImportDataRootElement()); Map<Long, Layout> layouts = (Map<Long, Layout>)portletDataContext.getNewPrimaryKeysMap( Layout.class + ".layout"); if (_log.isDebugEnabled()) { if (!portletElements.isEmpty()) { _log.debug("Deleting portlet data"); } } for (Element portletElement : portletElements) { long layoutId = GetterUtil.getLong( portletElement.attributeValue("layout-id")); long plid = LayoutConstants.DEFAULT_PLID; Layout layout = layouts.get(layoutId); if (layout != null) { plid = layout.getPlid(); } portletDataContext.setPlid(plid); portletDataContext.setPortletId( portletElement.attributeValue("portlet-id")); _portletImportController.deletePortletData(portletDataContext); } } protected void doImportFile( PortletDataContext portletDataContext, long userId) throws Exception { Map<String, String[]> parameterMap = portletDataContext.getParameterMap(); Group group = _groupLocalService.getGroup( portletDataContext.getGroupId()); String layoutsImportMode = MapUtil.getString( parameterMap, PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE, PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE_MERGE_BY_LAYOUT_UUID); boolean permissions = MapUtil.getBoolean( parameterMap, PortletDataHandlerKeys.PERMISSIONS); if (group.isLayoutSetPrototype()) { parameterMap.put( PortletDataHandlerKeys.LAYOUT_SET_PROTOTYPE_LINK_ENABLED, new String[] {Boolean.FALSE.toString()}); } if (_log.isDebugEnabled()) { _log.debug("Import permissions " + permissions); } StopWatch stopWatch = new StopWatch(); stopWatch.start(); LayoutCache layoutCache = new LayoutCache(); long companyId = portletDataContext.getCompanyId(); ServiceContext serviceContext = ServiceContextThreadLocal.getServiceContext(); if (serviceContext == null) { serviceContext = new ServiceContext(); } serviceContext.setCompanyId(companyId); serviceContext.setSignedIn(false); serviceContext.setUserId(userId); ServiceContextThreadLocal.pushServiceContext(serviceContext); // LAR validation validateFile( companyId, portletDataContext.getGroupId(), parameterMap, portletDataContext.getZipReader()); // Source and target group id Map<Long, Long> groupIds = (Map<Long, Long>)portletDataContext.getNewPrimaryKeysMap( Group.class); groupIds.put( portletDataContext.getSourceGroupId(), portletDataContext.getGroupId()); // Manifest ManifestSummary manifestSummary = ExportImportHelperUtil.getManifestSummary(portletDataContext); portletDataContext.setManifestSummary(manifestSummary); // Layout and layout set prototype Element rootElement = portletDataContext.getImportDataRootElement(); Element headerElement = rootElement.element("header"); String layoutSetPrototypeUuid = headerElement.attributeValue( "layout-set-prototype-uuid"); String larType = headerElement.attributeValue("type"); portletDataContext.setType(larType); if (group.isLayoutPrototype() && larType.equals("layout-prototype")) { parameterMap.put( PortletDataHandlerKeys.DELETE_MISSING_LAYOUTS, new String[] {Boolean.FALSE.toString()}); LayoutPrototype layoutPrototype = _layoutPrototypeLocalService.getLayoutPrototype( group.getClassPK()); String layoutPrototypeUuid = GetterUtil.getString( headerElement.attributeValue("type-uuid")); LayoutPrototype existingLayoutPrototype = null; if (Validator.isNotNull(layoutPrototypeUuid)) { try { existingLayoutPrototype = _layoutPrototypeLocalService. getLayoutPrototypeByUuidAndCompanyId( layoutPrototypeUuid, companyId); } catch (NoSuchLayoutPrototypeException nslpe) { // LPS-52675 if (_log.isDebugEnabled()) { _log.debug(nslpe, nslpe); } } } if (existingLayoutPrototype == null) { List<Layout> layouts = _layoutLocalService.getLayoutsByLayoutPrototypeUuid( layoutPrototype.getUuid()); layoutPrototype.setUuid(layoutPrototypeUuid); _layoutPrototypeLocalService.updateLayoutPrototype( layoutPrototype); for (Layout layout : layouts) { layout.setLayoutPrototypeUuid(layoutPrototypeUuid); _layoutLocalService.updateLayout(layout); } } } else if (group.isLayoutSetPrototype() && larType.equals("layout-set-prototype")) { parameterMap.put( PortletDataHandlerKeys.LAYOUT_SET_PROTOTYPE_SETTINGS, new String[] {Boolean.TRUE.toString()}); LayoutSetPrototype layoutSetPrototype = _layoutSetPrototypeLocalService.getLayoutSetPrototype( group.getClassPK()); String importedLayoutSetPrototypeUuid = GetterUtil.getString( headerElement.attributeValue("type-uuid")); LayoutSetPrototype existingLayoutSetPrototype = null; if (Validator.isNotNull(importedLayoutSetPrototypeUuid)) { try { existingLayoutSetPrototype = _layoutSetPrototypeLocalService. getLayoutSetPrototypeByUuidAndCompanyId( importedLayoutSetPrototypeUuid, companyId); } catch (NoSuchLayoutSetPrototypeException nslspe) { // LPS-52675 if (_log.isDebugEnabled()) { _log.debug(nslspe, nslspe); } } } if (existingLayoutSetPrototype == null) { List<LayoutSet> layoutSets = _layoutSetLocalService. getLayoutSetsByLayoutSetPrototypeUuid( layoutSetPrototype.getUuid()); layoutSetPrototype.setUuid(importedLayoutSetPrototypeUuid); _layoutSetPrototypeLocalService.updateLayoutSetPrototype( layoutSetPrototype); for (LayoutSet curLayoutSet : layoutSets) { curLayoutSet.setLayoutSetPrototypeUuid( importedLayoutSetPrototypeUuid); _layoutSetLocalService.updateLayoutSet(curLayoutSet); } } } else if (larType.equals("layout-set-prototype")) { parameterMap.put( PortletDataHandlerKeys.LAYOUT_SET_PROTOTYPE_SETTINGS, new String[] {Boolean.TRUE.toString()}); layoutSetPrototypeUuid = GetterUtil.getString( headerElement.attributeValue("type-uuid")); } if (Validator.isNotNull(layoutSetPrototypeUuid)) { portletDataContext.setLayoutSetPrototypeUuid( layoutSetPrototypeUuid); } List<Element> portletElements = fetchPortletElements(rootElement); if (permissions) { for (Element portletElement : portletElements) { String portletPath = portletElement.attributeValue("path"); Document portletDocument = SAXReaderUtil.read( portletDataContext.getZipEntryAsString(portletPath)); _permissionImporter.checkRoles( layoutCache, companyId, portletDataContext.getGroupId(), userId, portletDocument.getRootElement()); } _permissionImporter.readPortletDataPermissions(portletDataContext); } if (!layoutsImportMode.equals( PortletDataHandlerKeys. LAYOUTS_IMPORT_MODE_CREATED_FROM_PROTOTYPE)) { _portletImportController.readExpandoTables(portletDataContext); } _portletImportController.readLocks(portletDataContext); // Import the group Element groupsElement = portletDataContext.getImportDataGroupElement( StagedGroup.class); for (Element groupElement : groupsElement.elements()) { StagedModelDataHandlerUtil.importStagedModel( portletDataContext, groupElement); } // Asset links _portletImportController.importAssetLinks(portletDataContext); // Site _groupLocalService.updateSite(portletDataContext.getGroupId(), true); if (_log.isInfoEnabled()) { _log.info("Importing layouts takes " + stopWatch.getTime() + " ms"); } ZipReader zipReader = portletDataContext.getZipReader(); zipReader.close(); } protected List<Element> fetchPortletElements(Element rootElement) { List<Element> portletElements = new ArrayList<>(); // Site portlets Element sitePortletsElement = rootElement.element("site-portlets"); // LAR compatibility if (sitePortletsElement == null) { sitePortletsElement = rootElement.element("portlets"); } portletElements.addAll(sitePortletsElement.elements("portlet")); // Layout portlets XPath xPath = SAXReaderUtil.createXPath( "staged-model/portlets/portlet"); Element layoutsElement = rootElement.element( Layout.class.getSimpleName()); List<Node> nodes = xPath.selectNodes(layoutsElement); Stream<Node> nodesStream = nodes.stream(); nodesStream.map((node) -> (Element)node).forEach(portletElements::add); return portletElements; } protected PortletDataContext getPortletDataContext( ExportImportConfiguration exportImportConfiguration, File file) throws PortalException { Map<String, Serializable> settingsMap = exportImportConfiguration.getSettingsMap(); long userId = MapUtil.getLong(settingsMap, "userId"); long targetGroupId = MapUtil.getLong(settingsMap, "targetGroupId"); boolean privateLayout = MapUtil.getBoolean( settingsMap, "privateLayout"); Map<String, String[]> parameterMap = (Map<String, String[]>)settingsMap.get("parameterMap"); Group group = _groupLocalService.getGroup(targetGroupId); String userIdStrategyString = MapUtil.getString( parameterMap, PortletDataHandlerKeys.USER_ID_STRATEGY); UserIdStrategy userIdStrategy = ExportImportHelperUtil.getUserIdStrategy( userId, userIdStrategyString); ZipReader zipReader = ZipReaderFactoryUtil.getZipReader(file); PortletDataContext portletDataContext = PortletDataContextFactoryUtil.createImportPortletDataContext( group.getCompanyId(), targetGroupId, parameterMap, userIdStrategy, zipReader); portletDataContext.setExportImportProcessId( String.valueOf( exportImportConfiguration.getExportImportConfigurationId())); portletDataContext.setPrivateLayout(privateLayout); return portletDataContext; } protected int getProcessFlag() { if (ExportImportThreadLocal.isLayoutStagingInProcess()) { return PROCESS_FLAG_LAYOUT_STAGING_IN_PROCESS; } return PROCESS_FLAG_LAYOUT_IMPORT_IN_PROCESS; } /** * @deprecated As of 4.0.0 */ @Deprecated protected void importLayout( PortletDataContext portletDataContext, List<String> sourceLayoutsUuids, Element layoutElement) throws Exception { } protected void populateDeletionStagedModelTypes( PortletDataContext portletDataContext) throws Exception { List<Element> portletElements = fetchPortletElements( portletDataContext.getImportDataRootElement()); for (Element portletElement : portletElements) { String portletId = portletElement.attributeValue("portlet-id"); Portlet portlet = _portletLocalService.getPortletById( portletDataContext.getCompanyId(), portletId); if ((portlet == null) || !portlet.isActive() || portlet.isUndeployedPortlet()) { continue; } PortletDataHandler portletDataHandler = _portletDataHandlerProvider.provide( portletDataContext.getCompanyId(), portletId); if (portletDataHandler == null) { continue; } portletDataContext.addDeletionSystemEventStagedModelTypes( portletDataHandler.getDeletionSystemEventStagedModelTypes()); } portletDataContext.addDeletionSystemEventStagedModelTypes( new StagedModelType(Layout.class)); } /** * @deprecated As of 4.0.0 */ @Deprecated protected void setExportImportLifecycleManager( ExportImportLifecycleManager exportImportLifecycleManager) { } /** * @deprecated As of 4.0.0 */ @Deprecated protected void setGroupLocalService(GroupLocalService groupLocalService) { } /** * @deprecated As of 4.0.0 */ @Deprecated protected void setLayoutLocalService( LayoutLocalService layoutLocalService) { } /** * @deprecated As of 4.0.0 */ @Deprecated protected void setLayoutPrototypeLocalService( LayoutPrototypeLocalService layoutPrototypeLocalService) { } /** * @deprecated As of 4.0.0 */ @Deprecated protected void setLayoutSetLocalService( LayoutSetLocalService layoutSetLocalService) { } /** * @deprecated As of 4.0.0 */ @Deprecated protected void setLayoutSetPrototypeLocalService( LayoutSetPrototypeLocalService layoutSetPrototypeLocalService) { } /** * @deprecated As of 4.0.0 */ @Deprecated protected void setPortletImportController( PortletImportController portletImportController) { } /** * @deprecated As of 4.0.0 */ @Deprecated protected void setPortletLocalService( PortletLocalService portletLocalService) { } /** * @deprecated As of 4.0.0 */ @Deprecated protected void setPortletScope( PortletDataContext portletDataContext, Element portletElement) { } /** * @deprecated As of 4.0.0 */ @Deprecated protected void updateLayoutPriorities( PortletDataContext portletDataContext, List<Element> layoutElements, boolean privateLayout) { } protected void validateFile( long companyId, long groupId, Map<String, String[]> parameterMap, ZipReader zipReader) throws Exception { // XML String xml = zipReader.getEntryAsString("/manifest.xml"); if (xml == null) { throw new LARFileException(LARFileException.TYPE_MISSING_MANIFEST); } Element rootElement = null; try { Document document = SAXReaderUtil.read(xml); rootElement = document.getRootElement(); } catch (Exception e) { throw new LARFileException( LARFileException.TYPE_INVALID_MANIFEST, e); } // Bundle compatibility Element headerElement = rootElement.element("header"); int importBuildNumber = GetterUtil.getInteger( headerElement.attributeValue("build-number")); if (importBuildNumber < ReleaseInfo.RELEASE_7_0_0_BUILD_NUMBER) { int buildNumber = ReleaseInfo.getBuildNumber(); if (buildNumber != importBuildNumber) { throw new LayoutImportException( LayoutImportException.TYPE_WRONG_BUILD_NUMBER, new Object[] {importBuildNumber, buildNumber}); } } else { BiPredicate<Version, Version> majorVersionBiPredicate = (currentVersion, importVersion) -> Objects.equals( currentVersion.getMajor(), importVersion.getMajor()); BiPredicate<Version, Version> minorVersionBiPredicate = (currentVersion, importVersion) -> { int currentMinorVersion = GetterUtil.getInteger( currentVersion.getMinor(), -1); int importedMinorVersion = GetterUtil.getInteger( importVersion.getMinor(), -1); if (((currentMinorVersion == -1) && (importedMinorVersion == -1)) || (currentMinorVersion < importedMinorVersion)) { return false; } return true; }; BiPredicate<Version, Version> manifestVersionBiPredicate = (currentVersion, importVersion) -> { BiPredicate<Version, Version> versionBiPredicate = majorVersionBiPredicate.and(minorVersionBiPredicate); return versionBiPredicate.test( currentVersion, importVersion); }; String importSchemaVersion = GetterUtil.getString( headerElement.attributeValue("schema-version"), "1.0.0"); if (!manifestVersionBiPredicate.test( Version.getInstance( ExportImportConstants.EXPORT_IMPORT_SCHEMA_VERSION), Version.getInstance(importSchemaVersion))) { throw new LayoutImportException( LayoutImportException.TYPE_WRONG_LAR_SCHEMA_VERSION, new Object[] { importSchemaVersion, ExportImportConstants.EXPORT_IMPORT_SCHEMA_VERSION }); } } // Type String larType = headerElement.attributeValue("type"); String[] expectedLARTypes = new String[] { "layout-prototype", "layout-set", "layout-set-prototype" }; if (Stream.of(expectedLARTypes).noneMatch(lt -> lt.equals(larType))) { throw new LARTypeException(larType, expectedLARTypes); } Group group = _groupLocalService.fetchGroup(groupId); String layoutsImportMode = MapUtil.getString( parameterMap, PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE); if (larType.equals("layout-prototype") && !group.isLayoutPrototype() && !layoutsImportMode.equals( PortletDataHandlerKeys. LAYOUTS_IMPORT_MODE_CREATED_FROM_PROTOTYPE)) { throw new LARTypeException(LARTypeException.TYPE_LAYOUT_PROTOTYPE); } if (larType.equals("layout-set")) { if (group.isLayoutPrototype() || group.isLayoutSetPrototype()) { throw new LARTypeException(LARTypeException.TYPE_LAYOUT_SET); } long sourceCompanyGroupId = GetterUtil.getLong( headerElement.attributeValue("company-group-id")); long sourceGroupId = GetterUtil.getLong( headerElement.attributeValue("group-id")); boolean companySourceGroup = false; if (sourceCompanyGroupId == sourceGroupId) { companySourceGroup = true; } else if ((group.isStaged() || group.hasStagingGroup()) && !(group.isStagedRemotely() && group.hasRemoteStagingGroup())) { Group sourceGroup = _groupLocalService.fetchGroup( sourceGroupId); companySourceGroup = sourceGroup.isCompany(); } if (group.isCompany() ^ companySourceGroup) { throw new LARTypeException(LARTypeException.TYPE_COMPANY_GROUP); } } if (larType.equals("layout-set-prototype") && !group.isLayoutSetPrototype() && !layoutsImportMode.equals( PortletDataHandlerKeys. LAYOUTS_IMPORT_MODE_CREATED_FROM_PROTOTYPE)) { throw new LARTypeException( LARTypeException.TYPE_LAYOUT_SET_PROTOTYPE); } // Portlets compatibility List<Element> portletElements = fetchPortletElements(rootElement); for (Element portletElement : portletElements) { String portletId = GetterUtil.getString( portletElement.attributeValue("portlet-id")); if (Validator.isNull(portletId)) { continue; } String schemaVersion = GetterUtil.getString( portletElement.attributeValue("schema-version")); PortletDataHandler portletDataHandler = _portletDataHandlerProvider.provide(companyId, portletId); if (portletDataHandler == null) { continue; } if (!portletDataHandler.validateSchemaVersion(schemaVersion)) { throw new LayoutImportException( LayoutImportException.TYPE_WRONG_PORTLET_SCHEMA_VERSION, new Object[] { schemaVersion, portletId, portletDataHandler.getSchemaVersion() }); } } // Available locales List<Locale> sourceAvailableLocales = Arrays.asList( LocaleUtil.fromLanguageIds( StringUtil.split( headerElement.attributeValue("available-locales")))); for (Locale sourceAvailableLocale : sourceAvailableLocales) { if (!LanguageUtil.isAvailableLocale( groupId, sourceAvailableLocale)) { LocaleException le = new LocaleException( LocaleException.TYPE_EXPORT_IMPORT); le.setSourceAvailableLocales(sourceAvailableLocales); le.setTargetAvailableLocales( LanguageUtil.getAvailableLocales(groupId)); throw le; } } // Layout prototypes validity Element layoutsElement = rootElement.element( Layout.class.getSimpleName()); validateLayoutPrototypes(companyId, headerElement, layoutsElement); } /** * @deprecated As of 3.0.0, replaced by {@link * #validateLayoutPrototypes(long, Element, Element)} */ @Deprecated protected void validateLayoutPrototypes( long companyId, Element layoutsElement) throws Exception { throw new UnsupportedOperationException( "This method is deprecated and replaced by " + "#validateLayoutPrototypes(long, Element, Element)"); } protected void validateLayoutPrototypes( long companyId, Element headerElement, Element layoutsElement) throws Exception { List<Tuple> missingLayoutPrototypes = new ArrayList<>(); String layoutSetPrototypeUuid = headerElement.attributeValue( "layout-set-prototype-uuid"); if (Validator.isNotNull(layoutSetPrototypeUuid)) { try { _layoutSetPrototypeLocalService. getLayoutSetPrototypeByUuidAndCompanyId( layoutSetPrototypeUuid, companyId); } catch (NoSuchLayoutSetPrototypeException nslspe) { // LPS-52675 if (_log.isDebugEnabled()) { _log.debug(nslspe, nslspe); } String layoutSetPrototypeName = headerElement.attributeValue( "layout-set-prototype-name"); missingLayoutPrototypes.add( new Tuple( LayoutSetPrototype.class.getName(), layoutSetPrototypeUuid, layoutSetPrototypeName)); } } List<Element> layoutElements = layoutsElement.elements(); for (Element layoutElement : layoutElements) { String action = layoutElement.attributeValue(Constants.ACTION); if (action.equals(Constants.SKIP)) { continue; } String layoutPrototypeUuid = GetterUtil.getString( layoutElement.attributeValue("layout-prototype-uuid")); if (Validator.isNotNull(layoutPrototypeUuid)) { try { _layoutPrototypeLocalService. getLayoutPrototypeByUuidAndCompanyId( layoutPrototypeUuid, companyId); } catch (NoSuchLayoutPrototypeException nslpe) { // LPS-52675 if (_log.isDebugEnabled()) { _log.debug(nslpe, nslpe); } String layoutPrototypeName = GetterUtil.getString( layoutElement.attributeValue("layout-prototype-name")); missingLayoutPrototypes.add( new Tuple( LayoutPrototype.class.getName(), layoutPrototypeUuid, layoutPrototypeName)); } } } if (!missingLayoutPrototypes.isEmpty()) { throw new LayoutPrototypeException(missingLayoutPrototypes); } } private static final Log _log = LogFactoryUtil.getLog( LayoutImportController.class); private final DeletionSystemEventImporter _deletionSystemEventImporter = DeletionSystemEventImporter.getInstance(); @Reference private ExportImportLifecycleManager _exportImportLifecycleManager; @Reference private GroupLocalService _groupLocalService; @Reference private LayoutLocalService _layoutLocalService; @Reference private LayoutPrototypeLocalService _layoutPrototypeLocalService; @Reference private LayoutSetLocalService _layoutSetLocalService; @Reference private LayoutSetPrototypeLocalService _layoutSetPrototypeLocalService; private final PermissionImporter _permissionImporter = PermissionImporter.getInstance(); @Reference private PortletDataHandlerProvider _portletDataHandlerProvider; @Reference private PortletImportController _portletImportController; @Reference private PortletLocalService _portletLocalService; }