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.Date; 019import java.util.HashMap; 020import java.util.Map; 021 022import org.apache.avalon.framework.service.ServiceException; 023import org.apache.avalon.framework.service.ServiceManager; 024 025import org.ametys.cms.ObservationConstants; 026import org.ametys.cms.content.CopyContentMetadataComponent; 027import org.ametys.cms.content.CopyReport; 028import org.ametys.cms.repository.Content; 029import org.ametys.cms.repository.ModifiableContent; 030import org.ametys.cms.repository.WorkflowAwareContent; 031import org.ametys.cms.workflow.AbstractContentWorkflowComponent; 032import org.ametys.core.observation.Event; 033import org.ametys.core.observation.ObservationManager; 034import org.ametys.core.user.UserIdentity; 035import org.ametys.plugins.repository.AmetysRepositoryException; 036import org.ametys.plugins.repository.lock.LockHelper; 037import org.ametys.plugins.repository.lock.LockableAmetysObject; 038 039import com.opensymphony.module.propertyset.PropertySet; 040import com.opensymphony.workflow.FunctionProvider; 041import com.opensymphony.workflow.WorkflowException; 042 043/** 044 * Workflow function to edit a content using the duplication functionality 045 */ 046public class EditContentByCopyFunction extends AbstractContentWorkflowComponent implements FunctionProvider 047{ 048 /** Constant for storing the base content used for the duplication into the transient variables map. */ 049 public static final String BASE_CONTENT_KEY = EditContentByCopyFunction.class.getName() + "$baseContent"; 050 051 /** Constant for storing the map containing the duplication info into the transient variables map. */ 052 public static final String COPY_MAP_KEY = EditContentByCopyFunction.class.getName() + "$copyProperties"; 053 /** Constant for storing the copy report object into the transient variables map. */ 054 public static final String COPY_REPORT_KEY = EditContentByCopyFunction.class.getName() + "$copyReport"; 055 056 /** The metadata copy component */ 057 protected CopyContentMetadataComponent _copyContentMetadataHelper; 058 /** The observation manager */ 059 protected ObservationManager _observationManager; 060 061 @Override 062 public void service(ServiceManager manager) throws ServiceException 063 { 064 super.service(manager); 065 _copyContentMetadataHelper = (CopyContentMetadataComponent) manager.lookup(CopyContentMetadataComponent.ROLE); 066 _observationManager = (ObservationManager) _manager.lookup(ObservationManager.ROLE); 067 } 068 069 @Override 070 public void execute(Map transientVars, Map args, PropertySet ps) throws WorkflowException 071 { 072 WorkflowAwareContent content = getContent(transientVars); 073 UserIdentity user = getUser(transientVars); 074 075 if (!(content instanceof ModifiableContent)) 076 { 077 throw new IllegalArgumentException("The provided content " + content.getId() + " is not a ModifiableContent."); 078 } 079 080 ModifiableContent modifiableContent = (ModifiableContent) content; 081 082 try 083 { 084 LockableAmetysObject lockableContent = null; 085 if (content instanceof LockableAmetysObject) 086 { 087 lockableContent = (LockableAmetysObject) content; 088 if (lockableContent.isLocked() && !LockHelper.isLockOwner(lockableContent, user)) 089 { 090 throw new WorkflowException("User '" + user + "' try to save content '" + modifiableContent.getName() + "' but it is locked by another user"); 091 } 092 } 093 094 _duplicateMetadata(transientVars, modifiableContent); 095 096 _updateCommonMetadata(modifiableContent, user); 097 098 // Commit changes 099 modifiableContent.saveChanges(); 100 101 // Notify the observers of the modification. 102 Map<String, Object> eventParams = new HashMap<>(); 103 eventParams.put(ObservationConstants.ARGS_CONTENT, modifiableContent); 104 eventParams.put(ObservationConstants.ARGS_CONTENT_ID, modifiableContent.getId()); 105 106 _observationManager.notify(new Event(ObservationConstants.EVENT_CONTENT_MODIFIED, getUser(transientVars), eventParams)); 107 108 // Unlock content 109 if (lockableContent != null && lockableContent.isLocked()) 110 { 111 lockableContent.unlock(); 112 } 113 114 getResultsMap(transientVars).put("result", "ok"); 115 } 116 catch (AmetysRepositoryException e) 117 { 118 throw new WorkflowException("Unable to edit content " + modifiableContent + " from the repository", e); 119 } 120 } 121 122 /** 123 * Duplicate the currently edited content by copying the metadata of the source content. 124 * @param transientVars the transient variables. 125 * @param content the destination content. 126 * @throws WorkflowException if an error occurs. 127 */ 128 @SuppressWarnings("unchecked") 129 protected void _duplicateMetadata(Map transientVars, ModifiableContent content) throws WorkflowException 130 { 131 Content baseContent = (Content) transientVars.get(BASE_CONTENT_KEY); 132 CopyReport copyReport = (CopyReport) transientVars.get(COPY_REPORT_KEY); 133 Map<String, Object> copyMap = (Map<String, Object>) transientVars.get(COPY_MAP_KEY); 134 135 _copyContentMetadataHelper.copyMetadataMap(baseContent, content, copyMap, copyReport); 136 } 137 138 /** 139 * Updates common metadata (last contributor, last modification date, ...). 140 * @param content the content. 141 * @param user the user. 142 * @throws WorkflowException if an error occurs. 143 */ 144 protected void _updateCommonMetadata(ModifiableContent content, UserIdentity user) throws WorkflowException 145 { 146 if (user != null) 147 { 148 content.setLastContributor(user); 149 } 150 content.setLastModified(new Date()); 151 152 if (content instanceof WorkflowAwareContent) 153 { 154 // Remove the proposal date. 155 ((WorkflowAwareContent) content).setProposalDate(null); 156 } 157 } 158}