001/* 002 * Copyright 2016 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.support; 017 018import java.util.ArrayList; 019import java.util.Date; 020import java.util.HashSet; 021import java.util.Iterator; 022import java.util.List; 023import java.util.Set; 024 025import org.apache.avalon.framework.component.Component; 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; 030 031import com.opensymphony.workflow.AbstractWorkflow; 032import com.opensymphony.workflow.FactoryException; 033import com.opensymphony.workflow.Workflow; 034import com.opensymphony.workflow.WorkflowException; 035import com.opensymphony.workflow.loader.ActionDescriptor; 036import com.opensymphony.workflow.loader.StepDescriptor; 037import com.opensymphony.workflow.loader.WorkflowDescriptor; 038import com.opensymphony.workflow.spi.Step; 039import com.opensymphony.workflow.spi.WorkflowStore; 040 041/** 042 * Helper to get information on the workflow structures 043 */ 044public class WorkflowHelper extends AbstractLogEnabled implements Component, Serviceable 045{ 046 /** The Avalon role */ 047 public static final String ROLE = WorkflowHelper.class.getName(); 048 049 /** The content types extension point */ 050 protected WorkflowProvider _workflowProvider; 051 052 @Override 053 public void service(ServiceManager smanager) throws ServiceException 054 { 055 _workflowProvider = (WorkflowProvider) smanager.lookup(WorkflowProvider.ROLE); 056 } 057 058 /** 059 * Get a list of workflow names available 060 * @return String[] an array of workflow names. 061 */ 062 public String[] getWorkflowNames() 063 { 064 try 065 { 066 return _workflowProvider.getWorkflowFactory().getWorkflowNames(); 067 } 068 catch (FactoryException e) 069 { 070 getLogger().error("Error getting workflow names", e); 071 } 072 073 return new String[0]; 074 } 075 076 /** 077 * Returns a workflow definition object associated with the given name. 078 * @param workflowName the name of the workflow 079 * @return the object graph that represents a workflow definition 080 */ 081 public WorkflowDescriptor getWorkflowDescriptor(String workflowName) 082 { 083 try 084 { 085 return _workflowProvider.getWorkflowFactory().getWorkflow(workflowName); 086 } 087 catch (FactoryException e) 088 { 089 getLogger().error("Error loading workflow " + workflowName, e); 090 } 091 092 return null; 093 } 094 095 /** 096 * Retrieves all actions of the workflow of a particular type of workflow 097 * except initial actions. 098 * @param workflowName the name of the workflow. 099 * @return all actions ids. 100 * @throws IllegalArgumentException If the workflow name is not valid. 101 */ 102 public int[] getAllActions(String workflowName) throws IllegalArgumentException 103 { 104 WorkflowDescriptor workflowDesc = getWorkflowDescriptor(workflowName); 105 106 if (workflowDesc == null) 107 { 108 throw new IllegalArgumentException("Bad workflow name \"" + workflowName + "\""); 109 } 110 111 Set<Integer> actions = new HashSet<>(); 112 113 // Récupérer des actions globales 114 Iterator iterGlobalActions = workflowDesc.getGlobalActions().iterator(); 115 116 // Parcourir la liste des actions globales 117 while (iterGlobalActions.hasNext()) 118 { 119 // Récupérer la description de l'action globale courante 120 ActionDescriptor actionDesc = (ActionDescriptor) iterGlobalActions.next(); 121 122 // Ajouter l'action globale courante 123 actions.add(Integer.valueOf(actionDesc.getId())); 124 } 125 126 // Récupérer la liste des steps 127 Iterator iterSteps = workflowDesc.getSteps().iterator(); 128 129 // Parcourir la liste des steps 130 while (iterSteps.hasNext()) 131 { 132 // Récupérer le step courant 133 StepDescriptor stepDesc = (StepDescriptor) iterSteps.next(); 134 135 // Récupérer la liste des actions associés au step courant 136 Iterator iterActions = stepDesc.getActions().iterator(); 137 138 // Parcourir la liste des actions 139 while (iterActions.hasNext()) 140 { 141 // Récupérer la description de chaque action 142 ActionDescriptor actionDesc = (ActionDescriptor) iterActions.next(); 143 144 // Ajouter l'action courante 145 actions.add(Integer.valueOf(actionDesc.getId())); 146 } 147 } 148 149 // Convertir la liste en tableau d'entier 150 int[] array = new int[actions.size()]; 151 Iterator<Integer> itAction = actions.iterator(); 152 153 // Remplir le tableau 154 for (int i = 0; itAction.hasNext(); i++) 155 { 156 array[i] = itAction.next().intValue(); 157 } 158 159 return array; 160 } 161 162 /** 163 * Retrieves the name of an action. 164 * @param workflowName The name of the workflow. 165 * @param actionID The id of the action. 166 * @return The name of the action or an empty string. 167 */ 168 public String getActionName(String workflowName, int actionID) 169 { 170 // Récupérer la description du workflow 171 WorkflowDescriptor workflowDesc = getWorkflowDescriptor(workflowName); 172 173 if (workflowDesc == null) 174 { 175 return ""; 176 } 177 178 // Récupérer la description de l'action 179 ActionDescriptor actionDesc = workflowDesc.getAction(actionID); 180 181 if (actionDesc == null) 182 { 183 return ""; 184 } 185 186 return actionDesc.getName(); 187 } 188 189 /** 190 * Retrieves the name of a step. 191 * @param workflowName the name of the workflow. 192 * @param stepId the id of the step. 193 * @return the name of the step or an empty string. 194 */ 195 public String getStepName(String workflowName, int stepId) 196 { 197 // Récupérer la description du workflow 198 WorkflowDescriptor workflowDesc = getWorkflowDescriptor(workflowName); 199 200 if (workflowDesc == null) 201 { 202 return ""; 203 } 204 205 // Récupérer la description de l'action 206 StepDescriptor stepDesc = workflowDesc.getStep(stepId); 207 208 if (stepDesc == null) 209 { 210 return ""; 211 } 212 213 return stepDesc.getName(); 214 } 215 216 /** 217 * Retrieves the initial action id of a workflow. 218 * @param workflowName the name of the workflow. 219 * @return the first initial action id or <code>-1</code> 220 * if the workflow does not exist. 221 */ 222 public int getInitialAction(String workflowName) 223 { 224 // Récupérer la description du workflow 225 WorkflowDescriptor workflowDesc = getWorkflowDescriptor(workflowName); 226 227 if (workflowDesc == null) 228 { 229 return -1; 230 } 231 232 // Retourner la première action initiale 233 return ((ActionDescriptor) workflowDesc.getInitialActions().get(0)).getId(); 234 } 235 236 /** 237 * Retrieves the action ids from a particular step. 238 * @param workflowName the name of the workflow. 239 * @param stepId the id of the step. 240 * @return the ids of the actions of the step. 241 */ 242 public int[] getAllActionsFromStep(String workflowName, int stepId) 243 { 244 // Récupérer la description du workflow 245 WorkflowDescriptor workflowDesc = getWorkflowDescriptor(workflowName); 246 247 if (workflowDesc == null) 248 { 249 return new int[0]; 250 } 251 252 List<Integer> actions = new ArrayList<>(); 253 254 // Vérifier que l'identifiant est valide 255 StepDescriptor stepDesc = workflowDesc.getStep(stepId); 256 257 if (stepDesc == null) 258 { 259 return new int[0]; 260 } 261 262 // Récupérer la liste des actions associés au step courant 263 Iterator iterator = stepDesc.getActions().iterator(); 264 265 // Parcourir la liste des actions 266 while (iterator.hasNext()) 267 { 268 // Récupérer la description de chaque action 269 ActionDescriptor actionDesc = (ActionDescriptor) iterator.next(); 270 271 // Ajouter l'action courante 272 actions.add(Integer.valueOf(actionDesc.getId())); 273 } 274 275 // Récupérer les actions globales 276 iterator = workflowDesc.getGlobalActions().iterator(); 277 278 // Parcourir la liste des actions globales 279 while (iterator.hasNext()) 280 { 281 // Récupérer la description de l'action globale courante 282 ActionDescriptor actionDesc = (ActionDescriptor) iterator.next(); 283 284 // Ajouter l'action globale courant 285 actions.add(Integer.valueOf(actionDesc.getId())); 286 } 287 288 // Convertir la liste en tableau d'entier 289 int[] array = new int[actions.size()]; 290 291 // Remplir le tableau 292 for (int i = 0; i < array.length; i++) 293 { 294 array[i] = actions.get(i).intValue(); 295 } 296 297 return array; 298 } 299 300 /** 301 * Get the steps the workflow was "in" at a given date. 302 * @param workflow workflow 303 * @param entryId the workflow entry ID. 304 * @param timestamp the date. 305 * @return the list of steps the workflow was in. 306 * @throws WorkflowException if an error occurs. 307 */ 308 public List<Step> getStepAt(Workflow workflow, long entryId, Date timestamp) throws WorkflowException 309 { 310 return getStepsBetween(workflow, entryId, timestamp, timestamp); 311 } 312 313 /** 314 * Get the steps the workflow was "in" between two dates. 315 * @param workflow workflow 316 * @param entryId the workflow entry ID. 317 * @param start the start date. 318 * @param end the end date. 319 * @return the list of steps the workflow was in between the two dates. 320 * @throws WorkflowException if an error occurs. 321 */ 322 public List<Step> getStepsBetween(Workflow workflow, long entryId, Date start, Date end) throws WorkflowException 323 { 324 WorkflowStore store = ((AbstractWorkflow) workflow).getConfiguration().getWorkflowStore(); 325 326 List<Step> steps = new ArrayList<>(); 327 328 List<Step> allSteps = new ArrayList<>(); 329 330 allSteps.addAll(store.findCurrentSteps(entryId)); 331 allSteps.addAll(store.findHistorySteps(entryId)); 332 333 for (Step step : allSteps) 334 { 335 Date stepStartDate = step.getStartDate(); 336 Date stepFinishDate = step.getFinishDate(); 337 338 if (stepStartDate != null) 339 { 340 if (end.after(stepStartDate)) 341 { 342 if (stepFinishDate == null || start.before(stepFinishDate)) 343 { 344 steps.add(step); 345 } 346 } 347 } 348 else 349 { 350 if (stepFinishDate == null || start.before(stepFinishDate)) 351 { 352 steps.add(step); 353 } 354 } 355 } 356 357 return steps; 358 } 359} 360