001/* 002 * Copyright 2014 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.ArrayList; 019import java.util.HashMap; 020import java.util.Map; 021 022import org.apache.avalon.framework.component.Component; 023import org.apache.avalon.framework.context.Context; 024import org.apache.avalon.framework.context.ContextException; 025import org.apache.avalon.framework.context.Contextualizable; 026import org.apache.avalon.framework.logger.AbstractLogEnabled; 027import org.apache.avalon.framework.service.ServiceException; 028import org.apache.avalon.framework.service.ServiceManager; 029import org.apache.avalon.framework.service.Serviceable; 030import org.apache.cocoon.components.ContextHelper; 031import org.apache.cocoon.environment.ObjectModelHelper; 032import org.apache.cocoon.environment.Request; 033 034import org.ametys.cms.repository.Content; 035import org.ametys.cms.repository.WorkflowAwareContent; 036import org.ametys.core.user.CurrentUserProvider; 037import org.ametys.core.user.UserIdentity; 038import org.ametys.plugins.repository.AmetysRepositoryException; 039import org.ametys.plugins.workflow.AbstractWorkflowComponent; 040import org.ametys.plugins.workflow.support.WorkflowProvider; 041import org.ametys.plugins.workflow.support.WorkflowProvider.AmetysObjectWorkflow; 042 043import com.opensymphony.workflow.InvalidActionException; 044import com.opensymphony.workflow.WorkflowException; 045 046/** 047 * A component to do workflow actions on Content 048 */ 049public class ContentWorkflowHelper extends AbstractLogEnabled implements Serviceable, Contextualizable, Component 050{ 051 /** The component role */ 052 public static final String ROLE = ContentWorkflowHelper.class.getName(); 053 054 /** Component to get the current user */ 055 protected CurrentUserProvider _userProvider; 056 057 /** Workflow instance. */ 058 protected WorkflowProvider _workflowProvider; 059 060 private Context _context; 061 062 063 @Override 064 public void contextualize(Context context) throws ContextException 065 { 066 _context = context; 067 } 068 069 @Override 070 public void service(ServiceManager manager) throws ServiceException 071 { 072 _userProvider = (CurrentUserProvider) manager.lookup(CurrentUserProvider.ROLE); 073 _workflowProvider = (WorkflowProvider) manager.lookup(WorkflowProvider.ROLE); 074 } 075 076 /** 077 * Creates a content using the workflow (with the CreateContentFunction). 078 * @param workflowName The name of the workflow to create 079 * @param initialActionId The workflow action id that creates content 080 * @param contentName The new name 081 * @param contentTitle The new title 082 * @param contentTypes The new content types. Cannot be null. Cannot be empty. 083 * @param mixins The new mixins. Can be null. Can be empty. 084 * @param languageCode The language code of the new content (such as 'fr', 'en'...) 085 * @return The workflow result map. See the create content function used to get the new content. Can be under the key CreateContentFunction.CONTENT_KEY, and the id under the key "contentId" 086 * @throws WorkflowException If an error occurred while doing the action on the workflow 087 * @throws AmetysRepositoryException If cannot get the workflow identifier of the content 088 */ 089 public Map<String, Object> createContent(String workflowName, int initialActionId, String contentName, String contentTitle, String[] contentTypes, String[] mixins, String languageCode) throws AmetysRepositoryException, WorkflowException 090 { 091 return createContent(workflowName, initialActionId, contentName, contentTitle, contentTypes, mixins, languageCode, null, null); 092 } 093 094 /** 095 * Creates a content using the workflow (with the CreateContentFunction). 096 * @param workflowName The name of the workflow to create 097 * @param initialActionId The workflow action id that creates content 098 * @param contentName The new name 099 * @param contentTitle The new title 100 * @param contentTypes The new content types. Cannot be null. Cannot be empty. 101 * @param mixins The new mixins. Can be null. Can be empty. 102 * @param languageCode The language code of the new content (such as 'fr', 'en'...) 103 * @param parentContentId If the new content is a subcontent, the parent content identifier. 104 * @param parentContentMetadatapath If the new content is a subcontent, the path of the metadata where the new content will take place in its parent 105 * @return The workflow result map. See the create content function used to get the new content. Can be under the key CreateContentFunction.CONTENT_KEY, and the id under the key "contentId" 106 * @throws WorkflowException If an error occurred while doing the action on the workflow 107 * @throws AmetysRepositoryException If cannot get the workflow identifier of the content 108 109 */ 110 public Map<String, Object> createContent(String workflowName, int initialActionId, String contentName, String contentTitle, String[] contentTypes, String[] mixins, String languageCode, String parentContentId, String parentContentMetadatapath) throws AmetysRepositoryException, WorkflowException 111 { 112 Map<String, Object> inputs = new HashMap<>(); 113 return createContent(workflowName, initialActionId, contentName, contentTitle, contentTypes, mixins, languageCode, parentContentId, parentContentMetadatapath, inputs); 114 } 115 116 /** 117 * Creates a content using the workflow (with the CreateContentFunction). 118 * @param workflowName The name of the workflow to create 119 * @param initialActionId The workflow action id that creates content 120 * @param contentName The new name 121 * @param contentTitle The new title 122 * @param contentTypes The new content types. Cannot be null. Cannot be empty. 123 * @param mixins The new mixins. Can be null. Can be empty. 124 * @param languageCode The language code of the new content (such as 'fr', 'en'...) 125 * @param parentContentId If the new content is a subcontent, the parent content identifier. 126 * @param parentContentMetadatapath If the new content is a subcontent, the path of the metadata where the new content will take place in its parent 127 * @param inputs The parameters to transmit to the workflow functions. Cannot be null. 128 * @return The workflow result map. See the create content function used to get the new content. Can be under the key CreateContentFunction.CONTENT_KEY, and the id under the key "contentId" 129 * @throws WorkflowException If an error occurred while doing the action on the workflow 130 * @throws AmetysRepositoryException If cannot get the workflow identifier of the content 131 132 */ 133 public Map<String, Object> createContent(String workflowName, int initialActionId, String contentName, String contentTitle, String[] contentTypes, String[] mixins, String languageCode, String parentContentId, String parentContentMetadatapath, Map<String, Object> inputs) throws AmetysRepositoryException, WorkflowException 134 { 135 inputs.put(CreateContentFunction.CONTENT_NAME_KEY, contentName); 136 inputs.put(CreateContentFunction.CONTENT_TITLE_KEY, contentTitle); 137 inputs.put(CreateContentFunction.CONTENT_TYPES_KEY, contentTypes); 138 inputs.put(CreateContentFunction.CONTENT_MIXINS_KEY, mixins); 139 inputs.put(CreateContentFunction.CONTENT_LANGUAGE_KEY, languageCode); 140 inputs.put(CreateContentFunction.PARENT_CONTENT_ID_KEY, parentContentId); 141 inputs.put(CreateContentFunction.PARENT_CONTENT_METADATA_PATH_KEY, parentContentMetadatapath); 142 143 Map<String, Object> results = new HashMap<>(); 144 inputs.put(AbstractWorkflowComponent.RESULT_MAP_KEY, results); 145 inputs.put(AbstractWorkflowComponent.FAIL_CONDITIONS_KEY, new ArrayList<String>()); 146 147 try 148 { 149 AmetysObjectWorkflow workflow = _workflowProvider.getAmetysObjectWorkflow(); 150 workflow.initialize(workflowName, initialActionId, inputs); 151 } 152 catch (WorkflowException e) 153 { 154 getLogger().error("An error occured while creating workflow '" + workflowName + "' with action '" + initialActionId + "' to creates content '" + contentName + "'", e); 155 throw e; 156 } 157 158 return results; 159 } 160 161 /** 162 * Get the available workflow actions for the content 163 * @param content The content to consider. Cannot be null. 164 * @return The array of actions ids that are available now 165 */ 166 public int[] getAvailableActions(WorkflowAwareContent content) 167 { 168 Map<String, Object> inputs = new HashMap<>(); 169 return getAvailableActions(content, inputs); 170 } 171 172 /** 173 * Get the available workflow actions for the content 174 * @param content The content to consider. Cannot be null. 175 * @param inputs The parameters to transmit to the workflow functions. Cannot be null. 176 * @return The array of actions ids that are available now 177 */ 178 public int[] getAvailableActions(WorkflowAwareContent content, Map<String, Object> inputs) 179 { 180 AmetysObjectWorkflow workflow = _workflowProvider.getAmetysObjectWorkflow(content); 181 long wId = content.getWorkflowId(); 182 183 inputs.put(AbstractContentWorkflowComponent.CONTENT_KEY, content); 184 inputs.put(AbstractWorkflowComponent.FAIL_CONDITIONS_KEY, new ArrayList<String> ()); 185 186 return workflow.getAvailableActions(wId, inputs); 187 } 188 189 /** 190 * Do a workflow action on a content. 191 * @param content The content to act on. Cannot be null. 192 * @param actionId The id of the workflow action to do 193 * @return The results of the functions 194 * @throws WorkflowException If an error occurred while doing the action on the workflow 195 * @throws AmetysRepositoryException If cannot get the workflow identifier of the content 196 */ 197 public Map<String, Object> doAction(WorkflowAwareContent content, int actionId) throws AmetysRepositoryException, WorkflowException 198 { 199 Map<String, Object> inputs = new HashMap<>(); 200 return doAction(content, actionId, inputs); 201 } 202 203 /** 204 * Do a workflow action on a content. 205 * @param content The content to act on. Cannot be null. 206 * @param actionId The id of the workflow action to do 207 * @param inputs The parameters to transmit to the workflow functions. Cannot be null. The special key AbstractWorkflowComponent.CONTEXT_PARAMETERS_KEY will be filled with the parent context if null (this means that if your are in a request dispatched, you will automatically get the js parameters). 208 * @return The results of the functions 209 * @throws WorkflowException If an error occurred while doing the action on the workflow 210 * @throws AmetysRepositoryException If cannot get the workflow identifier of the content 211 */ 212 public Map<String, Object> doAction(WorkflowAwareContent content, int actionId, Map<String, Object> inputs) throws AmetysRepositoryException, WorkflowException 213 { 214 if (getLogger().isInfoEnabled()) 215 { 216 getLogger().info("User " + _getUser() + " try to perform action " + actionId + " on content " + content.getId()); 217 } 218 219 Map<String, Object> results = new HashMap<>(); 220 inputs.put(AbstractWorkflowComponent.RESULT_MAP_KEY, results); 221 inputs.put(AbstractContentWorkflowComponent.CONTENT_KEY, content); 222 inputs.put(AbstractWorkflowComponent.FAIL_CONDITIONS_KEY, new ArrayList<String>()); 223 224 if (inputs.get(AbstractWorkflowComponent.CONTEXT_PARAMETERS_KEY) == null) 225 { 226 Map objectModel = ContextHelper.getObjectModel(_context); 227 @SuppressWarnings("unchecked") 228 Map<String, Object> jsParameters = (Map<String, Object>) objectModel.get(ObjectModelHelper.PARENT_CONTEXT); 229 inputs.put(AbstractWorkflowComponent.CONTEXT_PARAMETERS_KEY, jsParameters); 230 } 231 232 try 233 { 234 Request request = ContextHelper.getRequest(_context); 235 request.setAttribute(Content.class.getName(), content); 236 237 AmetysObjectWorkflow workflow = _workflowProvider.getAmetysObjectWorkflow(content); 238 workflow.doAction(content.getWorkflowId(), actionId, inputs); 239 } 240 catch (InvalidActionException e) 241 { 242 getLogger().error("An error occured while do workflow action '" + actionId + "' on content '" + content.getId() + "'", e); 243 throw e; 244 } 245 246 return results; 247 } 248 249 private UserIdentity _getUser() 250 { 251 return _userProvider.getUser(); 252 } 253}