001/*
002 *  Copyright 2010 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;
017
018import java.util.Collections;
019import java.util.Iterator;
020import java.util.Map;
021
022import org.apache.avalon.framework.parameters.Parameters;
023import org.apache.cocoon.environment.ObjectModelHelper;
024import org.apache.cocoon.environment.Redirector;
025import org.apache.cocoon.environment.Request;
026
027import org.ametys.cms.repository.WorkflowAwareContent;
028import org.ametys.core.user.CurrentUserProvider;
029import org.ametys.core.user.UserIdentity;
030import org.ametys.plugins.workflow.cocoon.WorkflowAction;
031import org.ametys.plugins.workflow.support.WorkflowProvider.AmetysObjectWorkflow;
032
033import com.opensymphony.workflow.InvalidInputException;
034import com.opensymphony.workflow.WorkflowException;
035import com.opensymphony.workflow.spi.Step;
036
037/**
038 * Action for firing a transition on a content's workflow.<p>
039 * The following parameters are supported:
040 * <dl>
041 *  <dt>actionId
042 *  <dd>the id of the action to fire
043 * </dl>
044 */
045public class ContentWorkflowAction extends WorkflowAction
046{
047    /** Component to get the current user */
048    protected CurrentUserProvider _userProvider;
049    
050    @Override
051    public void initialize() throws Exception
052    {
053        super.initialize();
054        _userProvider = (CurrentUserProvider) manager.lookup(CurrentUserProvider.ROLE);
055    }
056    
057    @Override
058    protected Map _act(Redirector redirector, Map objectModel, String source, Parameters parameters, int actionId, Map inputs) throws InvalidInputException, WorkflowException
059    {
060        // Store the current step id
061        WorkflowAwareContent content = _getContent(objectModel);
062        
063        if (getLogger().isInfoEnabled())
064        {
065            getLogger().info("User " + _getUser(objectModel) + " try to perform action " + actionId + " on content " + content.getId());
066        }
067        
068        AmetysObjectWorkflow workflow = _workflowProvider.getAmetysObjectWorkflow(content);
069        workflow.doAction(_getWorkflowId(objectModel, source, parameters), actionId, inputs);
070        return _getActionResult(redirector, objectModel, source, parameters);
071    }
072    
073    @Override
074    protected long _getWorkflowId(Map objectModel, String source, Parameters parameters)
075    {
076        return _getContent(objectModel).getWorkflowId();
077    }
078    
079    @Override
080    protected Map<String, Object> _getInputs(Redirector redirector, Map objectModel, String source, Parameters parameters) throws Exception
081    {
082        Request request = ObjectModelHelper.getRequest(objectModel);
083        Map<String, Object> inputs = super._getInputs(redirector, objectModel, source, parameters);
084
085        // Provide the content key
086        inputs.put(AbstractContentWorkflowComponent.CONTENT_KEY, _getContent(objectModel));
087        
088        // Set the workflow comment into the inputs.
089        inputs.put("comment", request.getParameter("comment"));
090        
091        return inputs;
092    }
093    
094    /**
095     * Retrieve the content to use.
096     * @param objectModel the object model.
097     * @return the content found.
098     */
099    protected WorkflowAwareContent _getContent(Map objectModel)
100    {
101        Request request = ObjectModelHelper.getRequest(objectModel);
102        return (WorkflowAwareContent) request.getAttribute(AbstractContentWorkflowComponent.CONTENT_KEY);
103    }
104    
105    /**
106     * Retrieve the user responsible of the call.
107     * @param objectModel the object model.
108     * @return the user responsible of the call.
109     */
110    protected UserIdentity _getUser (Map objectModel)
111    {
112        return _userProvider.getUser();
113    }
114    
115    @Override
116    protected Map _processWorkflowException(Redirector redirector, Map objectModel, String source, Parameters parameters, long actionId, WorkflowException e) throws Exception
117    {
118        if (e instanceof InvalidInputWorkflowException)
119        {
120            // Validation error
121            if (getLogger().isDebugEnabled())
122            {
123                getLogger().debug("Validation error while executing workflow action", e);
124            }
125            
126            return Collections.EMPTY_MAP;
127        }
128        else
129        {
130            // Real error
131            return super._processWorkflowException(redirector, objectModel, source, parameters, actionId, e);
132        }
133    }
134    
135    @Override
136    protected String _getExceptionContext(Map objectModel, String source, Parameters parameters)
137    {
138        return String.format("the workflow of instance id: '%d' / content '%s' / current step '%d' / user '%s'",
139                             _getWorkflowId(objectModel, source, parameters),
140                             _getContent(objectModel),
141                             _getCurrentStep(objectModel),
142                             _getUser(objectModel));
143    }
144    
145    /**
146     * Get the content current step
147     * @param objectModel The object model
148     * @return The content current step as 
149     */
150    protected long _getCurrentStep (Map objectModel)
151    {
152        try
153        {
154            WorkflowAwareContent content = _getContent(objectModel);
155            AmetysObjectWorkflow workflow = _workflowProvider.getAmetysObjectWorkflow(content);
156            
157            Iterator<Step> steps = workflow.getCurrentSteps(content.getWorkflowId()).iterator();
158            if (steps.hasNext())
159            {
160                return steps.next().getStepId();
161            }
162        }
163        catch (Exception e)
164        {
165            // Log as INFO and return -1, as it's just debug information.
166            getLogger().info("An error occurred retrieving a content's workflow steps.", e);
167        }
168        
169        return -1;
170    }
171}