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}