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.plugins.workflow;
017
018import java.util.HashMap;
019import java.util.List;
020import java.util.Map;
021import java.util.Optional;
022
023import org.apache.avalon.framework.logger.LogEnabled;
024import org.apache.avalon.framework.logger.Logger;
025import org.apache.avalon.framework.service.ServiceException;
026import org.apache.avalon.framework.service.ServiceManager;
027import org.apache.avalon.framework.service.Serviceable;
028
029import org.ametys.core.user.UserIdentity;
030import org.ametys.runtime.i18n.I18nizableText;
031import org.ametys.runtime.parameter.Errors;
032
033import com.opensymphony.workflow.WorkflowContext;
034import com.opensymphony.workflow.WorkflowException;
035
036/**
037 * Abstract class for easily retrieving environment components
038 * in a condition or a function.
039 */
040public abstract class AbstractWorkflowComponent implements LogEnabled, Serviceable
041{
042    /** Constant for storing the content into the transient variables map. */
043    public static final String CONTEXT_PARAMETERS_KEY = AbstractWorkflowComponent.class.getName() + "$Parameters";
044    
045    /** Constant for storing the result map into the transient variables map. */
046    public static final String RESULT_MAP_KEY = AbstractWorkflowComponent.class.getName() + ";resultMap";
047    
048    /** Constant for storing the content into the transient variables map. */
049    public static final String FAIL_CONDITIONS_KEY = AbstractWorkflowComponent.class.getName() + "$failConditions";
050    
051    /** Constant for storing the workflow errors in result map. */
052    public static final String WORKFLOW_ERRORS_KEY = "workflowErrors";
053    
054    /** Constant for storing the workflow warnings in result map. */
055    public static final String WORKFLOW_WARNS_KEY = "workflowWarnings";
056    
057    /** Service manager available to subclasses. */
058    protected ServiceManager _manager;
059    /** Logger available to subclasses. */
060    protected Logger _logger;
061     
062    @Override
063    public void enableLogging(Logger logger)
064    {
065        _logger = logger;
066    }
067    
068    @Override
069    public void service(ServiceManager manager) throws ServiceException
070    {
071        _manager = manager;
072    }
073    
074    /**
075     * Retrieve the user responsible of the call.
076     * @param transientVars the parameters from the call.
077     * @return the user responsible of the call.
078     * @throws WorkflowException if the user is not present.
079     */
080    public UserIdentity getUser(Map transientVars) throws WorkflowException
081    {
082        WorkflowContext workflowContext = (WorkflowContext) transientVars.get("context");
083
084        if (workflowContext == null)
085        {
086            throw new WorkflowException("Unable to get the workflow context");
087        }
088
089        return UserIdentity.stringToUserIdentity(workflowContext.getCaller());
090    }
091
092    /**
093     * Retrieve the workflow parameters map, or an empty map if there is no parameters
094     * @param transientVars the parameters from the call.
095     * @return the workflow parameters map
096     * @throws WorkflowException if the object model or the request is not present.
097     */
098    public Map<String, Object> getContextParameters(Map transientVars) throws WorkflowException
099    {
100        return Optional.ofNullable(transientVars.get(CONTEXT_PARAMETERS_KEY))
101            .filter(Map.class::isInstance)
102            .map(Map.class::cast)
103            .orElseGet(() -> new HashMap<>());
104    }
105    
106    /**
107     * Retrieve the list condition failures
108     * @param transientVars the parameters from the call.
109     * @return the list of failed condition
110     * @throws WorkflowException If an error occurred
111     */
112    @SuppressWarnings("unchecked")
113    public List<String> getConditionFailures (Map transientVars) throws WorkflowException
114    {
115        return (List<String>) transientVars.get(FAIL_CONDITIONS_KEY);
116    }
117    
118    /**
119     * Retrieve the map to write return values
120     * @param transientVars the parameters from the call.
121     * @return the map to render.
122     * @throws WorkflowException if the result map is not found.
123     */
124    @SuppressWarnings("unchecked")
125    public Map<String, Object> getResultsMap(Map transientVars) throws WorkflowException
126    {
127        Map<String, Object> resultMap = (Map<String, Object>) transientVars.get(RESULT_MAP_KEY);
128        
129        if (resultMap == null)
130        {
131            throw new WorkflowException("Unable to retrieve result map");
132        }
133        
134        // Found in transient variables map
135        return resultMap;
136    }
137    
138    /**
139     * Add a global workflow error such as fail condition
140     * @param transientVars the parameters from the call.
141     * @param errorLabel The error label
142     * @throws WorkflowException if the result map is not found.
143     */
144    @SuppressWarnings("cast")
145    public void addWorkflowError (Map transientVars, I18nizableText errorLabel) throws WorkflowException
146    {
147        Map<String, Object> resultMap = (Map<String, Object>) getResultsMap(transientVars);
148        if (!resultMap.containsKey(AbstractWorkflowComponent.WORKFLOW_ERRORS_KEY))
149        {
150            resultMap.put(AbstractWorkflowComponent.WORKFLOW_ERRORS_KEY, new Errors());
151        }
152        
153        Errors errors = (Errors) resultMap.get(AbstractWorkflowComponent.WORKFLOW_ERRORS_KEY);
154        errors.addError(errorLabel);
155    }
156    
157    /**
158     * Add a global workflow errors that will be traited as warnings
159     * @param transientVars the parameters from the call.
160     * @param warnLabel The warning label
161     * @throws WorkflowException if the result map is not found.
162     */
163    @SuppressWarnings("cast")
164    public void addWorkflowWarning (Map transientVars, I18nizableText warnLabel) throws WorkflowException
165    {
166        Map<String, Object> resultMap = (Map<String, Object>) getResultsMap(transientVars);
167        if (!resultMap.containsKey(AbstractWorkflowComponent.WORKFLOW_WARNS_KEY))
168        {
169            resultMap.put(AbstractWorkflowComponent.WORKFLOW_WARNS_KEY, new Errors());
170        }
171        
172        Errors errors = (Errors) resultMap.get(AbstractWorkflowComponent.WORKFLOW_WARNS_KEY);
173        errors.addError(warnLabel);
174    }
175}