/** * 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.dynamic.data.mapping.web.internal.exportimport.data.handler; import com.liferay.dynamic.data.mapping.constants.DDMPortletKeys; import com.liferay.dynamic.data.mapping.io.DDMFormJSONDeserializer; import com.liferay.dynamic.data.mapping.io.DDMFormLayoutJSONDeserializer; import com.liferay.dynamic.data.mapping.model.DDMDataProviderInstance; import com.liferay.dynamic.data.mapping.model.DDMDataProviderInstanceLink; import com.liferay.dynamic.data.mapping.model.DDMForm; import com.liferay.dynamic.data.mapping.model.DDMFormField; import com.liferay.dynamic.data.mapping.model.DDMFormFieldType; import com.liferay.dynamic.data.mapping.model.DDMFormLayout; import com.liferay.dynamic.data.mapping.model.DDMStructure; import com.liferay.dynamic.data.mapping.model.DDMStructureConstants; import com.liferay.dynamic.data.mapping.model.DDMStructureLayout; import com.liferay.dynamic.data.mapping.model.DDMStructureVersion; import com.liferay.dynamic.data.mapping.service.DDMDataProviderInstanceLinkLocalService; import com.liferay.dynamic.data.mapping.service.DDMDataProviderInstanceLocalService; import com.liferay.dynamic.data.mapping.service.DDMStructureLayoutLocalService; import com.liferay.dynamic.data.mapping.service.DDMStructureLocalService; import com.liferay.exportimport.kernel.lar.ExportImportPathUtil; import com.liferay.exportimport.kernel.lar.PortletDataContext; import com.liferay.exportimport.kernel.lar.PortletDataException; import com.liferay.exportimport.kernel.lar.StagedModelDataHandler; import com.liferay.exportimport.kernel.lar.StagedModelDataHandlerUtil; import com.liferay.exportimport.kernel.lar.StagedModelModifiedDateComparator; import com.liferay.exportimport.lar.BaseStagedModelDataHandler; import com.liferay.portal.kernel.dao.orm.QueryUtil; import com.liferay.portal.kernel.exception.PortalException; 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.service.ServiceContext; import com.liferay.portal.kernel.service.UserLocalService; import com.liferay.portal.kernel.util.ArrayUtil; import com.liferay.portal.kernel.util.DateUtil; import com.liferay.portal.kernel.util.GetterUtil; import com.liferay.portal.kernel.util.MapUtil; import com.liferay.portal.kernel.util.Portal; import com.liferay.portal.kernel.util.StringPool; import com.liferay.portal.kernel.util.StringUtil; import com.liferay.portal.kernel.xml.Element; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; /** * @author Mate Thurzo * @author Daniel Kocsis */ @Component( immediate = true, property = {"javax.portlet.name=" + DDMPortletKeys.DYNAMIC_DATA_MAPPING}, service = StagedModelDataHandler.class ) public class DDMStructureStagedModelDataHandler extends BaseStagedModelDataHandler<DDMStructure> { public static final String[] CLASS_NAMES = {DDMStructure.class.getName()}; @Override public void deleteStagedModel(DDMStructure structure) throws PortalException { _ddmStructureLocalService.deleteStructure(structure); } @Override public void deleteStagedModel( String uuid, long groupId, String className, String extraData) throws PortalException { DDMStructure ddmStructure = fetchStagedModelByUuidAndGroupId( uuid, groupId); if (ddmStructure != null) { deleteStagedModel(ddmStructure); } } @Override public DDMStructure fetchStagedModelByUuidAndGroupId( String uuid, long groupId) { return _ddmStructureLocalService.fetchDDMStructureByUuidAndGroupId( uuid, groupId); } @Override public List<DDMStructure> fetchStagedModelsByUuidAndCompanyId( String uuid, long companyId) { return _ddmStructureLocalService.getDDMStructuresByUuidAndCompanyId( uuid, companyId, QueryUtil.ALL_POS, QueryUtil.ALL_POS, new StagedModelModifiedDateComparator<DDMStructure>()); } @Override public String[] getClassNames() { return CLASS_NAMES; } @Override public String getDisplayName(DDMStructure structure) { return structure.getNameCurrentValue(); } @Override public Map<String, String> getReferenceAttributes( PortletDataContext portletDataContext, DDMStructure structure) { Map<String, String> referenceAttributes = new HashMap<>(); referenceAttributes.put( "referenced-class-name", structure.getClassName()); referenceAttributes.put("structure-key", structure.getStructureKey()); long defaultUserId = 0; try { defaultUserId = _userLocalService.getDefaultUserId( structure.getCompanyId()); } catch (Exception e) { return referenceAttributes; } boolean preloaded = false; if (defaultUserId == structure.getUserId()) { preloaded = true; } referenceAttributes.put("preloaded", String.valueOf(preloaded)); return referenceAttributes; } @Override public boolean validateReference( PortletDataContext portletDataContext, Element referenceElement) { validateMissingGroupReference(portletDataContext, referenceElement); String uuid = referenceElement.attributeValue("uuid"); Map<Long, Long> groupIds = (Map<Long, Long>)portletDataContext.getNewPrimaryKeysMap( Group.class); long groupId = GetterUtil.getLong( referenceElement.attributeValue("group-id")); groupId = MapUtil.getLong(groupIds, groupId); long classNameId = _portal.getClassNameId( referenceElement.attributeValue("referenced-class-name")); String structureKey = referenceElement.attributeValue("structure-key"); boolean preloaded = GetterUtil.getBoolean( referenceElement.attributeValue("preloaded")); DDMStructure existingStructure = fetchExistingStructure( uuid, groupId, classNameId, structureKey, preloaded); if (existingStructure == null) { return false; } return true; } @Override protected void doExportStagedModel( PortletDataContext portletDataContext, DDMStructure structure) throws Exception { Element structureElement = portletDataContext.getExportDataElement( structure); if (structure.getParentStructureId() != DDMStructureConstants.DEFAULT_PARENT_STRUCTURE_ID) { DDMStructure parentStructure = _ddmStructureLocalService.getStructure( structure.getParentStructureId()); StagedModelDataHandlerUtil.exportReferenceStagedModel( portletDataContext, structure, parentStructure, PortletDataContext.REFERENCE_TYPE_PARENT); } long defaultUserId = _userLocalService.getDefaultUserId( structure.getCompanyId()); if (defaultUserId == structure.getUserId()) { structureElement.addAttribute("preloaded", "true"); } exportDDMForm(portletDataContext, structure, structureElement); exportDDMDataProviderInstances( portletDataContext, structure, structureElement); exportDDMFormLayout(portletDataContext, structure, structureElement); portletDataContext.addClassedModel( structureElement, ExportImportPathUtil.getModelPath(structure), structure); } @Override protected void doImportMissingReference( PortletDataContext portletDataContext, Element referenceElement) throws PortletDataException { importMissingGroupReference(portletDataContext, referenceElement); String uuid = referenceElement.attributeValue("uuid"); Map<Long, Long> groupIds = (Map<Long, Long>)portletDataContext.getNewPrimaryKeysMap( Group.class); long groupId = GetterUtil.getLong( referenceElement.attributeValue("group-id")); groupId = MapUtil.getLong(groupIds, groupId); long classNameId = _portal.getClassNameId( referenceElement.attributeValue("referenced-class-name")); String structureKey = referenceElement.attributeValue("structure-key"); boolean preloaded = GetterUtil.getBoolean( referenceElement.attributeValue("preloaded")); DDMStructure existingStructure = null; existingStructure = fetchExistingStructure( uuid, groupId, classNameId, structureKey, preloaded); Map<Long, Long> structureIds = (Map<Long, Long>)portletDataContext.getNewPrimaryKeysMap( DDMStructure.class); long structureId = GetterUtil.getLong( referenceElement.attributeValue("class-pk")); structureIds.put(structureId, existingStructure.getStructureId()); Map<String, String> structureKeys = (Map<String, String>)portletDataContext.getNewPrimaryKeysMap( DDMStructure.class + ".ddmStructureKey"); structureKeys.put(structureKey, existingStructure.getStructureKey()); Map<String, String> structureUuids = (Map<String, String>)portletDataContext.getNewPrimaryKeysMap( DDMStructure.class + ".ddmStructureUuid"); structureUuids.put(uuid, existingStructure.getUuid()); } @Override protected void doImportStagedModel( PortletDataContext portletDataContext, DDMStructure structure) throws Exception { long userId = portletDataContext.getUserId(structure.getUserUuid()); Map<Long, Long> structureIds = (Map<Long, Long>)portletDataContext.getNewPrimaryKeysMap( DDMStructure.class); long parentStructureId = MapUtil.getLong( structureIds, structure.getParentStructureId(), structure.getParentStructureId()); Map<String, String> structureKeys = (Map<String, String>)portletDataContext.getNewPrimaryKeysMap( DDMStructure.class + ".ddmStructureKey"); Element structureElement = portletDataContext.getImportDataElement( structure); DDMForm ddmForm = getImportDDMForm( portletDataContext, structureElement); importDDMDataProviderInstances( portletDataContext, structureElement, ddmForm); DDMFormLayout ddmFormLayout = getImportDDMFormLayout( portletDataContext, structureElement); ServiceContext serviceContext = portletDataContext.createServiceContext( structure); DDMStructure importedStructure = null; Map<Long, Long> groupIds = (Map<Long, Long>)portletDataContext.getNewPrimaryKeysMap( Group.class); long targetGroupId = portletDataContext.getScopeGroupId(); if (groupIds.containsKey(structure.getGroupId())) { targetGroupId = groupIds.get(structure.getGroupId()); } if (portletDataContext.isDataStrategyMirror()) { Element element = portletDataContext.getImportDataStagedModelElement(structure); boolean preloaded = GetterUtil.getBoolean( element.attributeValue("preloaded")); DDMStructure existingStructure = fetchExistingStructure( structure.getUuid(), targetGroupId, structure.getClassNameId(), structure.getStructureKey(), preloaded); if (existingStructure == null) { serviceContext.setUuid(structure.getUuid()); // Force a new structure key if a structure with the same key // already exists existingStructure = _ddmStructureLocalService.fetchStructure( targetGroupId, structure.getClassNameId(), structure.getStructureKey()); if (existingStructure != null) { structure.setStructureKey(null); } importedStructure = _ddmStructureLocalService.addStructure( userId, targetGroupId, parentStructureId, structure.getClassNameId(), structure.getStructureKey(), structure.getNameMap(), structure.getDescriptionMap(), ddmForm, ddmFormLayout, structure.getStorageType(), structure.getType(), serviceContext); } else if (isModifiedStructure(existingStructure, structure)) { importedStructure = _ddmStructureLocalService.updateStructure( userId, existingStructure.getStructureId(), parentStructureId, structure.getNameMap(), structure.getDescriptionMap(), ddmForm, ddmFormLayout, serviceContext); } else { if (_log.isDebugEnabled()) { _log.debug( "Not importing DDM structure with key " + structure.getStructureKey() + " since it was not modified"); } importedStructure = existingStructure; } } else { importedStructure = _ddmStructureLocalService.addStructure( userId, targetGroupId, parentStructureId, structure.getClassNameId(), null, structure.getNameMap(), structure.getDescriptionMap(), ddmForm, ddmFormLayout, structure.getStorageType(), structure.getType(), serviceContext); } portletDataContext.importClassedModel(structure, importedStructure); structureKeys.put( structure.getStructureKey(), importedStructure.getStructureKey()); } protected void exportDDMDataProviderInstances( PortletDataContext portletDataContext, DDMStructure structure, Element structureElement) throws PortalException { Set<Long> ddmDataProviderInstanceIdsSet = new HashSet<>(); List<DDMDataProviderInstanceLink> ddmDataProviderInstanceLinks = _ddmDataProviderInstanceLinkLocalService. getDataProviderInstanceLinks(structure.getStructureId()); for (DDMDataProviderInstanceLink ddmDataProviderInstanceLink : ddmDataProviderInstanceLinks) { long ddmDataProviderInstanceId = ddmDataProviderInstanceLink.getDataProviderInstanceId(); DDMDataProviderInstance ddmDataProviderInstance = _ddmDataProviderInstanceLocalService.getDDMDataProviderInstance( ddmDataProviderInstanceId); StagedModelDataHandlerUtil.exportReferenceStagedModel( portletDataContext, structure, ddmDataProviderInstance, PortletDataContext.REFERENCE_TYPE_STRONG); ddmDataProviderInstanceIdsSet.add( ddmDataProviderInstance.getDataProviderInstanceId()); } String ddmDataProviderInstanceIds = ArrayUtil.toString( ddmDataProviderInstanceIdsSet.toArray( new Long[ddmDataProviderInstanceIdsSet.size()]), StringPool.BLANK); structureElement.addAttribute( _DDM_DATA_PROVIDER_INSTANCE_IDS, ddmDataProviderInstanceIds); } protected void exportDDMForm( PortletDataContext portletDataContext, DDMStructure structure, Element structureElement) { String ddmFormPath = ExportImportPathUtil.getModelPath( structure, "ddm-form.json"); structureElement.addAttribute("ddm-form-path", ddmFormPath); portletDataContext.addZipEntry(ddmFormPath, structure.getDefinition()); } protected void exportDDMFormLayout( PortletDataContext portletDataContext, DDMStructure structure, Element structureElement) throws PortalException { DDMStructureVersion structureVersion = structure.getStructureVersion(); DDMStructureLayout structureLayout = _ddmStructureLayoutLocalService. getStructureLayoutByStructureVersionId( structureVersion.getStructureVersionId()); String ddmFormLayoutPath = ExportImportPathUtil.getModelPath( structure, "ddm-form-layout.json"); structureElement.addAttribute( "ddm-form-layout-path", ddmFormLayoutPath); portletDataContext.addZipEntry( ddmFormLayoutPath, structureLayout.getDefinition()); } protected DDMStructure fetchExistingStructure( String uuid, long groupId, long classNameId, String structureKey, boolean preloaded) { DDMStructure existingStructure = null; if (!preloaded) { existingStructure = fetchStagedModelByUuidAndGroupId(uuid, groupId); } else { existingStructure = _ddmStructureLocalService.fetchStructure( groupId, classNameId, structureKey); } return existingStructure; } protected DDMForm getImportDDMForm( PortletDataContext portletDataContext, Element structureElement) throws PortalException { String ddmFormPath = structureElement.attributeValue("ddm-form-path"); String serializedDDMForm = portletDataContext.getZipEntryAsString( ddmFormPath); return _ddmFormJSONDeserializer.deserialize(serializedDDMForm); } protected DDMFormLayout getImportDDMFormLayout( PortletDataContext portletDataContext, Element structureElement) throws PortalException { String ddmFormLayoutPath = structureElement.attributeValue( "ddm-form-layout-path"); String serializedDDMFormLayout = portletDataContext.getZipEntryAsString( ddmFormLayoutPath); return _ddmFormLayoutJSONDeserializer.deserialize( serializedDDMFormLayout); } protected void importDDMDataProviderInstances( PortletDataContext portletDataContext, Element structureElement, DDMForm ddmForm) throws PortletDataException { String[] ddmDataProviderInstanceIds = StringUtil.split( structureElement.attributeValue(_DDM_DATA_PROVIDER_INSTANCE_IDS)); if (ArrayUtil.isEmpty(ddmDataProviderInstanceIds)) { return; } Map<Long, Long> dataProviderInstanceIdsMap = (Map<Long, Long>)portletDataContext.getNewPrimaryKeysMap( DDMDataProviderInstance.class); for (String ddmDataProviderInstanceId : ddmDataProviderInstanceIds) { long oldDDMDataProviderInstanceId = Long.parseLong( ddmDataProviderInstanceId); long newDDMDataProviderInstanceId = MapUtil.getLong( dataProviderInstanceIdsMap, oldDDMDataProviderInstanceId); StagedModelDataHandlerUtil.importReferenceStagedModel( portletDataContext, DDMDataProviderInstance.class, newDDMDataProviderInstanceId); } List<DDMFormField> ddmFormFields = ddmForm.getDDMFormFields(); for (DDMFormField ddmFormField : ddmFormFields) { if (!ddmFormField.getType().equals(DDMFormFieldType.SELECT)) { continue; } long oldDDMDataProviderInstanceId = Long.valueOf( String.valueOf( ddmFormField.getProperty("ddmDataProviderInstanceId"))); long newDDMDataProviderInstanceId = MapUtil.getLong( dataProviderInstanceIdsMap, oldDDMDataProviderInstanceId); ddmFormField.setProperty( "ddmDataProviderInstanceId", newDDMDataProviderInstanceId); } } protected boolean isModifiedStructure( DDMStructure existingStructure, DDMStructure structure) { // Check modified date first int value = DateUtil.compareTo( existingStructure.getModifiedDate(), structure.getModifiedDate()); if (value < 0) { return true; } // Check other attributes if (!Objects.equals( existingStructure.getDefinition(), structure.getDefinition())) { return true; } if (!Objects.equals( existingStructure.getDescriptionMap(), structure.getDescriptionMap())) { return true; } if (!Objects.equals( existingStructure.getNameMap(), structure.getNameMap())) { return true; } if (!Objects.equals( existingStructure.getStorageType(), structure.getStorageType())) { return true; } if (!Objects.equals(existingStructure.getType(), structure.getType())) { return true; } return false; } @Reference(unbind = "-") protected void setDDMFormJSONDeserializer( DDMFormJSONDeserializer ddmFormJSONDeserializer) { _ddmFormJSONDeserializer = ddmFormJSONDeserializer; } @Reference(unbind = "-") protected void setDDMFormLayoutJSONDeserializer( DDMFormLayoutJSONDeserializer ddmFormLayoutJSONDeserializer) { _ddmFormLayoutJSONDeserializer = ddmFormLayoutJSONDeserializer; } @Reference(unbind = "-") protected void setDDMStructureLayoutLocalService( DDMStructureLayoutLocalService ddmStructureLayoutLocalService) { _ddmStructureLayoutLocalService = ddmStructureLayoutLocalService; } @Reference(unbind = "-") protected void setDDMStructureLocalService( DDMStructureLocalService ddmStructureLocalService) { _ddmStructureLocalService = ddmStructureLocalService; } @Reference(unbind = "-") protected void setUserLocalService(UserLocalService userLocalService) { _userLocalService = userLocalService; } private static final String _DDM_DATA_PROVIDER_INSTANCE_IDS = "ddm-data-provider-instance-ids"; private static final Log _log = LogFactoryUtil.getLog( DDMStructureStagedModelDataHandler.class); @Reference private DDMDataProviderInstanceLinkLocalService _ddmDataProviderInstanceLinkLocalService; @Reference private DDMDataProviderInstanceLocalService _ddmDataProviderInstanceLocalService; private DDMFormJSONDeserializer _ddmFormJSONDeserializer; private DDMFormLayoutJSONDeserializer _ddmFormLayoutJSONDeserializer; private DDMStructureLayoutLocalService _ddmStructureLayoutLocalService; private DDMStructureLocalService _ddmStructureLocalService; @Reference private Portal _portal; private UserLocalService _userLocalService; }