001/* 002 * Copyright 2013 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.cms.workflow.copy; 017 018import java.util.HashMap; 019import java.util.Locale; 020import java.util.Map; 021import java.util.Map.Entry; 022 023import org.apache.avalon.framework.service.ServiceException; 024import org.apache.avalon.framework.service.ServiceManager; 025import org.apache.commons.lang3.StringUtils; 026 027import org.ametys.cms.content.CopyContentMetadataComponent; 028import org.ametys.cms.content.CopyReport; 029import org.ametys.cms.content.CopyReport.CopyMode; 030import org.ametys.cms.contenttype.ContentTypesHelper; 031import org.ametys.cms.repository.Content; 032import org.ametys.cms.repository.ModifiableContent; 033import org.ametys.cms.workflow.CreateContentFunction; 034import org.ametys.core.util.I18nUtils; 035import org.ametys.plugins.repository.UnknownAmetysObjectException; 036import org.ametys.runtime.i18n.I18nizableText; 037 038import com.opensymphony.module.propertyset.PropertySet; 039import com.opensymphony.workflow.WorkflowException; 040 041/** 042 * OSWorkflow function to create a content by copy of another 043 * 044 * The required transient variables: 045 * - CreateContentByCopyFunction.BASE_CONTENT_KEY - Content The content that will be used for duplication. 046 * - or CreateContentByCopyFunction.BASE_CONTENT_ID - String The id of content The content that will be used for duplication. 047 * 048 * - CreateContentByCopyFunction.COPY_MAP_KEY - Map<String, Object> The map of properties to copy. Can be null if CreateContentByCopyFunction.COPY_METADATASET_NAME is used 049 */ 050public class CreateContentByCopyFunction extends CreateContentFunction 051{ 052 /** Constant for storing the base content used for the duplication into the transient variables map. */ 053 public static final String BASE_CONTENT_KEY = CreateContentByCopyFunction.class.getName() + "$baseContent"; 054 055 /** Constant for storing the id of base content used for the duplication into the transient variables map. */ 056 public static final String BASE_CONTENT_ID = CreateContentByCopyFunction.class.getName() + "$baseContentId"; 057 058 /** Constant for storing the map containing the duplication info into the transient variables map. Can be null.*/ 059 public static final String COPY_MAP_KEY = CreateContentByCopyFunction.class.getName() + "$copyProperties"; 060 061 /** Constant for storing the copy report object into the transient variables map. Can be null. */ 062 public static final String COPY_REPORT_KEY = CreateContentByCopyFunction.class.getName() + "$copyReport"; 063 064 /** Constant for storing the name of metadata set to use for copy. */ 065 public static final String COPY_METADATASET_NAME = CreateContentByCopyFunction.class.getName() + "$metadataSetName"; 066 /** Constant for storing the name of fallback metadata set to use for copy. */ 067 public static final String COPY_FALLBACK_METADATASET_NAME = CreateContentByCopyFunction.class.getName() + "$fallbackMetadataSetName"; 068 /** Constant for storing the type of metadata set to use for copy. */ 069 public static final String COPY_METADATASET_TYPE = CreateContentByCopyFunction.class.getName() + "$metadataSetType"; 070 071 /** The metadata copy component */ 072 protected CopyContentMetadataComponent _copyContentMetadataHelper; 073 /** The content type helper */ 074 protected ContentTypesHelper _cTypesHelper; 075 076 /** I18n Utils */ 077 protected I18nUtils _i18nUtils; 078 079 @Override 080 public void service(ServiceManager manager) throws ServiceException 081 { 082 super.service(manager); 083 _copyContentMetadataHelper = (CopyContentMetadataComponent) manager.lookup(CopyContentMetadataComponent.ROLE); 084 _cTypesHelper = (ContentTypesHelper) manager.lookup(ContentTypesHelper.ROLE); 085 _i18nUtils = (I18nUtils) manager.lookup(I18nUtils.ROLE); 086 } 087 088 @SuppressWarnings("cast") 089 @Override 090 public void execute(Map transientVars, Map args, PropertySet ps) throws WorkflowException 091 { 092 // Preparation of the transientVars to work with the super method (CreateContentFunction). 093 Content baseContent = getBaseContentForCopy(transientVars); 094 095 if (baseContent == null) 096 { 097 throw new WorkflowException("Unable to retrieve the base content for the duplication."); 098 } 099 100 if (transientVars.get(CreateContentFunction.CONTENT_TITLE_KEY) == null) 101 { 102 if (_contentHelper.isMultilingual(baseContent)) 103 { 104 Map<String, String> titleVariants = new HashMap<>(); 105 Map<String, String> baseTitleVariants = _contentHelper.getTitleVariants(baseContent); 106 107 for (Entry<String, String> entry : baseTitleVariants.entrySet()) 108 { 109 titleVariants.put(entry.getKey(), entry.getValue() + _i18nUtils.translate(new I18nizableText("plugin.cms", "CONTENT_COPY_CREATE_CONTENT_TITLE_SUFFIX"))); 110 } 111 112 String defaultLang = (String) transientVars.get(CreateContentFunction.CONTENT_LANGUAGE_KEY); 113 Locale defaultLocale = StringUtils.isNotEmpty(defaultLang) ? new Locale(defaultLang) : new Locale(titleVariants.keySet().iterator().next()); 114 transientVars.put(CreateContentFunction.CONTENT_NAME_KEY, baseContent.getTitle(defaultLocale)); 115 transientVars.put(CreateContentFunction.CONTENT_TITLE_VARIANTS_KEY, titleVariants); 116 } 117 else 118 { 119 transientVars.put(CreateContentFunction.CONTENT_NAME_KEY, baseContent.getTitle(null)); 120 // If title is not set, the base title is set with a copy suffix. 121 transientVars.put(CreateContentFunction.CONTENT_TITLE_KEY, baseContent.getTitle(null) + _i18nUtils.translate(new I18nizableText("plugin.cms", "CONTENT_COPY_CREATE_CONTENT_TITLE_SUFFIX"))); 122 } 123 } 124 else 125 { 126 transientVars.put(CreateContentFunction.CONTENT_NAME_KEY, (String) transientVars.get(CreateContentFunction.CONTENT_TITLE_KEY)); 127 } 128 129 if (transientVars.get(CreateContentFunction.CONTENT_TYPES_KEY) == null) 130 { 131 transientVars.put(CreateContentFunction.CONTENT_TYPES_KEY, baseContent.getTypes()); 132 } 133 134 transientVars.put(CreateContentFunction.CONTENT_MIXINS_KEY, baseContent.getMixinTypes()); 135 transientVars.put(CreateContentFunction.CONTENT_LANGUAGE_KEY, baseContent.getLanguage()); 136 137 // Super method call. 138 super.execute(transientVars, args, ps); 139 } 140 141 /** 142 * Get the content 143 * @param transientVars The workflow transiant vars with BASE_CONTENT_KEY (the content itself) or BASE_CONTENT_ID (the id of the content) 144 * @return the content or null if the object cannot be found 145 */ 146 protected Content getBaseContentForCopy (Map transientVars) 147 { 148 Content baseContent = (Content) transientVars.get(BASE_CONTENT_KEY); 149 150 if (baseContent == null) 151 { 152 String baseContentId = (String) transientVars.get(BASE_CONTENT_ID); 153 154 try 155 { 156 baseContent = _resolver.resolveById(baseContentId); 157 } 158 catch (UnknownAmetysObjectException e) 159 { 160 return null; 161 } 162 } 163 164 return baseContent; 165 } 166 167 @Override 168 protected void _populateAdditionalData(Map transientVars, ModifiableContent content) throws WorkflowException 169 { 170 super._populateAdditionalData(transientVars, content); 171 172 // This is where the duplication process is made. After the new content has been created. 173 Content baseContent = getBaseContentForCopy(transientVars); 174 175 String metadataSetName = StringUtils.defaultIfBlank((String) transientVars.get(COPY_METADATASET_NAME), "default-edition"); 176 String fallbackMetadataSetName = StringUtils.defaultIfBlank((String) transientVars.get(COPY_FALLBACK_METADATASET_NAME), "main"); 177 String metadataSetType = StringUtils.defaultIfBlank((String) transientVars.get(COPY_METADATASET_TYPE), "edition"); 178 179 if (!transientVars.containsKey(COPY_REPORT_KEY)) 180 { 181 transientVars.put(COPY_REPORT_KEY, new CopyReport(baseContent.getId(), _contentHelper.getTitle(baseContent), true, metadataSetName, fallbackMetadataSetName, metadataSetType, CopyMode.CREATION)); 182 } 183 CopyReport copyReport = (CopyReport) transientVars.get(COPY_REPORT_KEY); 184 185 Map<String, Object> copyMap = _buildCopyMap(transientVars, baseContent, metadataSetName, fallbackMetadataSetName, metadataSetType); 186 187 _copyContentMetadataHelper.copyMetadataMap(baseContent, content, copyMap, copyReport); 188 } 189 190 191 /** 192 * Get the builded copy map 193 * @param transientVars the vars 194 * @param baseContent the base content to be copied 195 * @param metadataSetName the metadata set name 196 * @param fallbackMetadataSetName the fallbacl metadata set name, if required metadata set does not exist 197 * @param metadataSetType the metadata set type 198 * @return the builded copy map 199 */ 200 @SuppressWarnings("unchecked") 201 protected Map<String, Object> _buildCopyMap(Map transientVars, Content baseContent, String metadataSetName, String fallbackMetadataSetName, String metadataSetType) 202 { 203 Map<String, Object> copyMap = (Map<String, Object>) transientVars.get(COPY_MAP_KEY); 204 if (copyMap == null) 205 { 206 copyMap = _copyContentMetadataHelper.buildCopyMap(baseContent, metadataSetName, fallbackMetadataSetName, metadataSetType); 207 } 208 209 return copyMap; 210 } 211}