View Javadoc
1   /*
2    * Copyright (c) 2002-2022, City of Paris
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met:
8    *
9    *  1. Redistributions of source code must retain the above copyright notice
10   *     and the following disclaimer.
11   *
12   *  2. Redistributions in binary form must reproduce the above copyright notice
13   *     and the following disclaimer in the documentation and/or other materials
14   *     provided with the distribution.
15   *
16   *  3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
17   *     contributors may be used to endorse or promote products derived from
18   *     this software without specific prior written permission.
19   *
20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
24   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   * POSSIBILITY OF SUCH DAMAGE.
31   *
32   * License 1.0
33   */
34  package fr.paris.lutece.plugins.workflow.web;
35  
36  import java.io.IOException;
37  import java.io.OutputStream;
38  import java.lang.reflect.InvocationTargetException;
39  import java.nio.charset.StandardCharsets;
40  import java.util.ArrayList;
41  import java.util.Arrays;
42  import java.util.Collection;
43  import java.util.Collections;
44  import java.util.Comparator;
45  import java.util.HashMap;
46  import java.util.LinkedHashSet;
47  import java.util.List;
48  import java.util.Locale;
49  import java.util.Map;
50  import java.util.UUID;
51  
52  import javax.servlet.http.HttpServletRequest;
53  import javax.servlet.http.HttpServletResponse;
54  
55  import org.apache.commons.collections.CollectionUtils;
56  import org.apache.commons.collections.iterators.EntrySetMapIterator;
57  import org.apache.commons.fileupload.FileItem;
58  import org.apache.commons.lang3.ArrayUtils;
59  import org.apache.commons.lang3.StringUtils;
60  
61  import com.fasterxml.jackson.core.JsonProcessingException;
62  
63  import fr.paris.lutece.api.user.User;
64  import fr.paris.lutece.plugins.workflow.business.prerequisite.PrerequisiteDTO;
65  import fr.paris.lutece.plugins.workflow.business.task.TaskRemovalListenerService;
66  import fr.paris.lutece.plugins.workflow.service.ActionResourceIdService;
67  import fr.paris.lutece.plugins.workflow.service.WorkflowGraphExportService;
68  import fr.paris.lutece.plugins.workflow.service.json.WorkflowJsonService;
69  import fr.paris.lutece.plugins.workflow.service.prerequisite.PrerequisiteManagementService;
70  import fr.paris.lutece.plugins.workflow.service.task.TaskFactory;
71  import fr.paris.lutece.plugins.workflow.utils.WorkflowUtils;
72  import fr.paris.lutece.plugins.workflow.web.task.TaskComponentManager;
73  import fr.paris.lutece.plugins.workflowcore.business.action.Action;
74  import fr.paris.lutece.plugins.workflowcore.business.action.ActionFilter;
75  import fr.paris.lutece.plugins.workflowcore.business.config.ITaskConfig;
76  import fr.paris.lutece.plugins.workflowcore.business.icon.Icon;
77  import fr.paris.lutece.plugins.workflowcore.business.prerequisite.Prerequisite;
78  import fr.paris.lutece.plugins.workflowcore.business.state.State;
79  import fr.paris.lutece.plugins.workflowcore.business.state.StateFilter;
80  import fr.paris.lutece.plugins.workflowcore.business.task.ITaskType;
81  import fr.paris.lutece.plugins.workflowcore.business.workflow.Workflow;
82  import fr.paris.lutece.plugins.workflowcore.business.workflow.WorkflowFilter;
83  import fr.paris.lutece.plugins.workflowcore.service.action.ActionService;
84  import fr.paris.lutece.plugins.workflowcore.service.action.IActionService;
85  import fr.paris.lutece.plugins.workflowcore.service.config.ITaskConfigService;
86  import fr.paris.lutece.plugins.workflowcore.service.icon.IIconService;
87  import fr.paris.lutece.plugins.workflowcore.service.icon.IconService;
88  import fr.paris.lutece.plugins.workflowcore.service.prerequisite.IAutomaticActionPrerequisiteService;
89  import fr.paris.lutece.plugins.workflowcore.service.prerequisite.IPrerequisiteManagementService;
90  import fr.paris.lutece.plugins.workflowcore.service.state.IStateService;
91  import fr.paris.lutece.plugins.workflowcore.service.state.StateService;
92  import fr.paris.lutece.plugins.workflowcore.service.task.ITask;
93  import fr.paris.lutece.plugins.workflowcore.service.task.ITaskFactory;
94  import fr.paris.lutece.plugins.workflowcore.service.task.ITaskService;
95  import fr.paris.lutece.plugins.workflowcore.service.task.TaskService;
96  import fr.paris.lutece.plugins.workflowcore.service.workflow.IWorkflowService;
97  import fr.paris.lutece.plugins.workflowcore.service.workflow.WorkflowService;
98  import fr.paris.lutece.plugins.workflowcore.web.task.ITaskComponentManager;
99  import fr.paris.lutece.portal.business.rbac.RBAC;
100 import fr.paris.lutece.portal.business.user.AdminUser;
101 import fr.paris.lutece.portal.service.admin.AccessDeniedException;
102 import fr.paris.lutece.portal.service.admin.AdminUserService;
103 import fr.paris.lutece.portal.service.i18n.I18nService;
104 import fr.paris.lutece.portal.service.message.AdminMessage;
105 import fr.paris.lutece.portal.service.message.AdminMessageService;
106 import fr.paris.lutece.portal.service.rbac.RBACService;
107 import fr.paris.lutece.portal.service.security.SecurityTokenService;
108 import fr.paris.lutece.portal.service.spring.SpringContextService;
109 import fr.paris.lutece.portal.service.template.AppTemplateService;
110 import fr.paris.lutece.portal.service.util.AppLogService;
111 import fr.paris.lutece.portal.service.util.AppPathService;
112 import fr.paris.lutece.portal.service.util.AppPropertiesService;
113 import fr.paris.lutece.portal.service.workflow.WorkflowRemovalListenerService;
114 import fr.paris.lutece.portal.service.workgroup.AdminWorkgroupService;
115 import fr.paris.lutece.portal.util.mvc.utils.MVCUtils;
116 import fr.paris.lutece.portal.web.admin.PluginAdminPageJspBean;
117 import fr.paris.lutece.portal.web.upload.MultipartHttpServletRequest;
118 import fr.paris.lutece.portal.web.util.LocalizedPaginator;
119 import fr.paris.lutece.util.ReferenceList;
120 import fr.paris.lutece.util.file.FileUtil;
121 import fr.paris.lutece.util.html.AbstractPaginator;
122 import fr.paris.lutece.util.html.HtmlTemplate;
123 import fr.paris.lutece.util.method.MethodUtil;
124 import fr.paris.lutece.util.url.UrlItem;
125 
126 /**
127  * class ManageDirectoryJspBean
128  */
129 public class WorkflowJspBean extends PluginAdminPageJspBean
130 {
131     /**
132      * Right to manage workflows
133      */
134     public static final String RIGHT_MANAGE_WORKFLOW = "WORKFLOW_MANAGEMENT";
135     private static final long serialVersionUID = -3521312136519134434L;
136 
137     // jsp
138     private static final String JSP_MODIFY_WORKFLOW = "jsp/admin/plugins/workflow/ModifyWorkflow.jsp";
139     private static final String JSP_MODIFY_TASK = "jsp/admin/plugins/workflow/ModifyTask.jsp";
140     private static final String JSP_MODIFY_ACTION = "jsp/admin/plugins/workflow/ModifyAction.jsp";
141     private static final String JSP_MODIFY_REFLEXIVE_ACTION = "jsp/admin/plugins/workflow/GetModifyReflexiveAction.jsp";
142     private static final String JSP_DO_REMOVE_WORKFLOW = "jsp/admin/plugins/workflow/DoRemoveWorkflow.jsp";
143     private static final String JSP_DO_REMOVE_STATE = "jsp/admin/plugins/workflow/DoRemoveState.jsp";
144     private static final String JSP_DO_REMOVE_ACTION = "jsp/admin/plugins/workflow/DoRemoveAction.jsp";
145     private static final String JSP_DO_COPY_WORKFLOW = "jsp/admin/plugins/workflow/DoCopyWorkflow.jsp";
146     private static final String JSP_DO_IMPORT_WORKFLOW = "jsp/admin/plugins/workflow/DoImportWorkflow.jsp";
147     private static final String JSP_DO_REMOVE_TASK = "jsp/admin/plugins/workflow/DoRemoveTask.jsp";
148     private static final String JSP_DO_REMOVE_TASK_FROM_REFLEXIVE_ACTION = "jsp/admin/plugins/workflow/DoRemoveTaskFromReflexiveAction.jsp";
149     private static final String JSP_MANAGE_WORKFLOW = "jsp/admin/plugins/workflow/ManageWorkflow.jsp";
150 
151     // templates
152     private static final String TEMPLATE_MANAGE_WORKFLOW = "admin/plugins/workflow/manage_workflow.html";
153     private static final String TEMPLATE_CREATE_WORKFLOW = "admin/plugins/workflow/create_workflow.html";
154     private static final String TEMPLATE_MODIFY_WORKFLOW = "admin/plugins/workflow/modify_workflow.html";
155     private static final String TEMPLATE_CREATE_STATE = "admin/plugins/workflow/create_state.html";
156     private static final String TEMPLATE_MODIFY_STATE = "admin/plugins/workflow/modify_state.html";
157     private static final String TEMPLATE_CREATE_ACTION = "admin/plugins/workflow/create_action.html";
158     private static final String TEMPLATE_MODIFY_ACTION = "admin/plugins/workflow/modify_action.html";
159     private static final String TEMPLATE_MODIFY_TASK = "admin/plugins/workflow/modify_task.html";
160     private static final String TEMPLATE_MANAGE_ADVANCED_PARAMETERS = "admin/plugins/workflow/manage_advanced_parameters.html";
161     private static final String TEMPLATE_MODIFY_REFLEXIVE_ACTION = "admin/plugins/workflow/modify_reflexive_action.html";
162 
163     // parameters
164     private static final String PARAMETER_IS_ENABLED = "is_enabled";
165     private static final String PARAMETER_IS_INITIAL_STATE = "is_initial_state";
166     private static final String PARAMETER_IS_REQUIRED_WORKGROUP_ASSIGNED = "is_required_workgroup_assigned";
167     private static final String PARAMETER_WORKGROUP = "workgroup";
168     private static final String PARAMETER_PAGE_INDEX = "page_index";
169     private static final String PARAMETER_NAME = "name";
170     private static final String PARAMETER_DESCRIPTION = "description";
171     private static final String PARAMETER_CANCEL = "cancel";
172     private static final String PARAMETER_ID_WORKFLOW = "id_workflow";
173     private static final String PARAMETER_ID_ACTION = "id_action";
174     private static final String PARAMETER_ID_STATE = "id_state";
175     private static final String PARAMETER_ID_TASK = "id_task";
176     private static final String PARAMETER_ID_ICON = "id_icon";
177     private static final String PARAMETER_ID_AUTOMATIC = "automatic";
178     private static final String PARAMETER_IS_MASS_ACTION = "is_mass_action";
179     private static final String PARAMETER_ID_STATE_BEFORE = "id_state_before";
180     private static final String PARAMETER_ID_STATE_AFTER = "id_state_after";
181     private static final String PARAMETER_ID_ALTERNATIVE_STATE_AFTER = "id_alternative_state_after";
182     private static final String PARAMETER_ORDER_ID = "order_id";
183     private static final String PARAMETER_ORDER_ACTION_ID = "order_action_id";
184     private static final String PARAMETER_ORDER_TASK_ID = "order_task_id";
185     private static final String PARAMETER_APPLY = "apply";
186     private static final String PARAMETER_PAGE_INDEX_STATE = "page_index_state";
187     private static final String PARAMETER_PAGE_INDEX_ACTION = "page_index_action";
188     private static final String PARAMETER_ITEMS_PER_PAGE_STATE = "items_per_page_state";
189     private static final String PARAMETER_ITEMS_PER_PAGE_ACTION = "items_per_page_action";
190     private static final String PARAMETER_TASK_TYPE_KEY = "task_type_key";
191     private static final String PARAMETER_SELECT_LINKED_ACTIONS = "select_linked_actions";
192     private static final String PARAMETER_UNSELECT_LINKED_ACTIONS = "unselect_linked_actions";
193     private static final String PARAMETER_PANE = "pane";
194     private static final String PARAMETER_JSON_FILE = "json_file";
195     private static final String PARAMETER_SHOW_TASKS = "show_tasks";
196 
197     // properties
198     private static final String PROPERTY_MANAGE_WORKFLOW_PAGE_TITLE = "workflow.manage_workflow.page_title";
199     private static final String PROPERTY_CREATE_WORKFLOW_PAGE_TITLE = "workflow.create_workflow.page_title";
200     private static final String PROPERTY_MODIFY_WORKFLOW_PAGE_TITLE = "workflow.modify_workflow.page_title";
201     private static final String PROPERTY_CREATE_STATE_PAGE_TITLE = "workflow.create_state.page_title";
202     private static final String PROPERTY_MODIFY_STATE_PAGE_TITLE = "workflow.modify_state.page_title";
203     private static final String PROPERTY_CREATE_ACTION_PAGE_TITLE = "workflow.create_action.page_title";
204     private static final String PROPERTY_MODIFY_ACTION_PAGE_TITLE = "workflow.modify_action.page_title";
205     private static final String PROPERTY_MODIFY_TASK_PAGE_TITLE = "workflow.modify_task.page_title";
206     private static final String PROPERTY_ITEM_PER_PAGE = "workflow.itemsPerPage";
207     private static final String PROPERTY_COPY_OF_STATE = "workflow.manage_workflow.copy_of_state";
208     private static final String PROPERTY_COPY_OF_ACTION = "workflow.manage_workflow.copy_of_action";
209     private static final String PROPERTY_ALL = "workflow.manage_workflow.select.all";
210     private static final String PROPERTY_YES = "workflow.manage_workflow.select.yes";
211     private static final String PROPERTY_NO = "workflow.manage_workflow.select.no";
212     private static final String FIELD_WORKFLOW_NAME = "workflow.create_workflow.label_name";
213     private static final String FIELD_ACTION_NAME = "workflow.create_action.label_name";
214     private static final String FIELD_STATE_NAME = "workflow.create_state.label_name";
215     private static final String FIELD_WORKFLOW_DESCRIPTION = "workflow.create_workflow.label_description";
216     private static final String FIELD_ACTION_DESCRIPTION = "workflow.create_action.label_description";
217     private static final String FIELD_STATE_DESCRIPTION = "workflow.create_state.label_description";
218     private static final String FIELD_STATE_BEFORE = "workflow.create_action.label_state_before";
219     private static final String FIELD_STATE_AFTER = "workflow.create_action.label_state_after";
220     private static final String FIELD_ICON = "workflow.create_action.label_icon";
221 
222     // mark
223     private static final String MARK_PLUGIN = "plugin";
224     private static final String MARK_PAGINATOR = "paginator";
225     private static final String MARK_PAGINATOR_ACTION = "paginator_action";
226     private static final String MARK_PAGINATOR_STATE = "paginator_state";
227     private static final String MARK_USER_WORKGROUP_REF_LIST = "user_workgroup_list";
228     private static final String MARK_USER_WORKGROUP_SELECTED = "user_workgroup_selected";
229     private static final String MARK_ACTIVE_REF_LIST = "active_list";
230     private static final String MARK_ACTIVE_SELECTED = "active_selected";
231     private static final String MARK_NB_ITEMS_PER_PAGE = "nb_items_per_page";
232     private static final String MARK_NB_ITEMS_PER_PAGE_ACTION = "nb_items_per_page_action";
233     private static final String MARK_NB_ITEMS_PER_PAGE_STATE = "nb_items_per_page_state";
234     private static final String MARK_WORKFLOW_LIST = "workflow_list";
235     private static final String MARK_STATE_LIST = "state_list";
236     private static final String MARK_ALTERNATIVE_STATE_LIST = "alternative_state_list";
237     private static final String MARK_ACTION_LIST = "action_list";
238     private static final String MARK_STATE_BEFORE_MAP = "state_before_map";
239     private static final String MARK_ICON_LIST = "icon_list";
240     private static final String MARK_TASK_TYPE_LIST = "task_type_list";
241     private static final String MARK_TASK_LIST = "task_list";
242     private static final String MARK_TASK_CONFIG = "task_config";
243     private static final String MARK_TASK = "task";
244     private static final String MARK_LOCALE = "locale";
245     private static final String MARK_WORKFLOW = "workflow";
246     private static final String MARK_STATE = "state";
247     private static final String MARK_NUMBER_STATE = "number_state";
248     private static final String MARK_NUMBER_ACTION = "number_action";
249     private static final String MARK_NUMBER_TASK = "number_task";
250     private static final String MARK_ACTION = "action";
251     private static final String MARK_INITIAL_STATE = "initial_state";
252     private static final String MARK_PERMISSION_MANAGE_ADVANCED_PARAMETERS = "permission_manage_advanced_parameters";
253     private static final String MARK_DEFAULT_VALUE_WORKGROUP_KEY = "workgroup_key_default_value";
254     private static final String MARK_AVAILABLE_LINKED_ACTIONS = "available_linked_actions";
255     private static final String MARK_SELECTED_LINKED_ACTIONS = "selected_linked_actions";
256     private static final String MARK_DISPLAY_TASKS_FORM = "display_tasks_form";
257     private static final String MARK_PANE = "pane";
258     private static final String MARK_PANE_ACTIONS = "pane-actions";
259     private static final String MARK_PANE_STATE = "pane-states";
260     private static final String MARK_LIST_PREREQUISITE_TYPE = "list_prerequisite_type";
261     private static final String MARK_LIST_PREREQUISITE = "listPrerequisite";
262     private static final String MARK_MDGRAPH = "mdgraph";
263     private static final String MARK_SHOW_TASKS = "showTasks";
264 
265     // MESSAGES
266     private static final String MESSAGE_ERROR_INVALID_SECURITY_TOKEN = "workflow.message.error.invalidSecurityToken";
267     private static final String MESSAGE_MANDATORY_FIELD = "workflow.message.mandatory.field";
268     private static final String MESSAGE_ERROR_AUTOMATIC_FIELD = "workflow.message.error.automatic.field";
269     private static final String MESSAGE_CONFIRM_REMOVE_WORKFLOW = "workflow.message.confirm_remove_workflow";
270     private static final String MESSAGE_CONFIRM_REMOVE_STATE = "workflow.message.confirm_remove_state";
271     private static final String MESSAGE_CONFIRM_REMOVE_ACTION = "workflow.message.confirm_remove_action";
272     private static final String MESSAGE_CONFIRM_REMOVE_TASK = "workflow.message.confirm_remove_task";
273     private static final String MESSAGE_CONFIRM_COPY_WORKFLOW = "workflow.message.confirm_copy_workflow";
274     private static final String MESSAGE_INITIAL_STATE_ALREADY_EXIST = "workflow.message.initial_state_already_exist";
275     private static final String MESSAGE_CAN_NOT_REMOVE_STATE_ACTIONS_ARE_ASSOCIATE = "workflow.message.can_not_remove_state_actions_are_associate";
276     private static final String MESSAGE_CAN_NOT_REMOVE_STATE_TASKS_ARE_ASSOCIATE = "workflow.message.can_not_remove_state_tasks_are_associate";
277     private static final String MESSAGE_CAN_NOT_REMOVE_WORKFLOW = "workflow.message.can_not_remove_workflow";
278     private static final String MESSAGE_CAN_NOT_REMOVE_TASK = "workflow.message.can_not_remove_task";
279     private static final String MESSAGE_CAN_NOT_DISABLE_WORKFLOW = "workflow.message.can_not_disable_workflow";
280     private static final String MESSAGE_TASK_IS_NOT_AUTOMATIC = "workflow.message.task_not_automatic";
281     private static final String MESSAGE_MASS_ACTION_CANNOT_BE_AUTOMATIC = "workflow.message.mass_action_cannot_be_automatic";
282     private static final String MESSAGE_REFLEXIVE_ACTION_NAME = "workflow.reflexive_action.defaultTitle";
283     private static final String PANE_STATES = "pane-states";
284     private static final String PANE_ACTIONS = "pane-actions";
285     private static final String PANE_DEFAULT = PANE_STATES;
286 
287     private static final String LOG_ACTION_NOT_FOUND = "Action not found for ID ";
288     private static final String LOG_WORKFLOW_NOT_FOUND = "Workflow not found for ID ";
289     
290     private static final String ERROR_NO_FILE_SELECTED = "workflow.message.error.no_file_selected";
291 
292     // session fields
293     private int _nDefaultItemsPerPage = AppPropertiesService.getPropertyInt( PROPERTY_ITEM_PER_PAGE, 50 );
294     private String _strCurrentPageIndexWorkflow;
295     private int _nItemsPerPageWorkflow;
296     private String _strCurrentPageIndexState;
297     private int _nItemsPerPageState;
298     private String _strCurrentPageIndexAction;
299     private int _nItemsPerPageAction;
300     private int _nIsEnabled = -1;
301     private String _strWorkGroup = AdminWorkgroupService.ALL_GROUPS;
302     private IWorkflowService _workflowService = SpringContextService.getBean( WorkflowService.BEAN_SERVICE );
303     private IStateService _stateService = SpringContextService.getBean( StateService.BEAN_SERVICE );
304     private IActionService _actionService = SpringContextService.getBean( ActionService.BEAN_SERVICE );
305     private IIconService _iconService = SpringContextService.getBean( IconService.BEAN_SERVICE );
306     private ITaskService _taskService = SpringContextService.getBean( TaskService.BEAN_SERVICE );
307     private ITaskFactory _taskFactory = SpringContextService.getBean( TaskFactory.BEAN_SERVICE );
308     private ITaskComponentManager _taskComponentManager = SpringContextService.getBean( TaskComponentManager.BEAN_MANAGER );
309     private IPrerequisiteManagementService _prerequisiteManagementService = SpringContextService.getBean( PrerequisiteManagementService.BEAN_NAME );
310     private FileItem _importWorkflowFile;
311 
312     /*-------------------------------MANAGEMENT  WORKFLOW-----------------------------*/
313 
314     /**
315      * Return management page of plugin workflow
316      * 
317      * @param request
318      *            The Http request
319      * @return Html management page of plugin workflow
320      */
321     public String getManageWorkflow( HttpServletRequest request )
322     {
323         setPageTitleProperty( WorkflowUtils.EMPTY_STRING );
324 
325         String strWorkGroup = request.getParameter( PARAMETER_WORKGROUP );
326         String strIsEnabled = request.getParameter( PARAMETER_IS_ENABLED );
327         _strCurrentPageIndexWorkflow = AbstractPaginator.getPageIndex( request, AbstractPaginator.PARAMETER_PAGE_INDEX, _strCurrentPageIndexWorkflow );
328         _nItemsPerPageWorkflow = AbstractPaginator.getItemsPerPage( request, AbstractPaginator.PARAMETER_ITEMS_PER_PAGE, _nItemsPerPageWorkflow,
329                 _nDefaultItemsPerPage );
330 
331         if ( ( strIsEnabled != null ) && !strIsEnabled.equals( WorkflowUtils.EMPTY_STRING ) )
332         {
333             _nIsEnabled = WorkflowUtils.convertStringToInt( strIsEnabled );
334         }
335 
336         if ( ( strWorkGroup != null ) && !strWorkGroup.equals( WorkflowUtils.EMPTY_STRING ) )
337         {
338             _strWorkGroup = strWorkGroup;
339         }
340 
341         // build Filter
342         WorkflowFilter filter = new WorkflowFilter( );
343         filter.setIsEnabled( _nIsEnabled );
344         filter.setWorkGroup( _strWorkGroup );
345 
346         List<Workflow> listWorkflow = _workflowService.getListWorkflowsByFilter( filter );
347         listWorkflow = (List<Workflow>) AdminWorkgroupService.getAuthorizedCollection( listWorkflow, (User) getUser( ) );
348         Collections.sort( listWorkflow, Comparator.comparing( Workflow::getName ) );
349 
350         LocalizedPaginator<Workflow> paginator = new LocalizedPaginator<>( listWorkflow, _nItemsPerPageWorkflow, getJspManageWorkflow( request ),
351                 PARAMETER_PAGE_INDEX, _strCurrentPageIndexWorkflow, getLocale( ) );
352 
353         boolean bPermissionAdvancedParameter = RBACService.isAuthorized( Action.RESOURCE_TYPE, RBAC.WILDCARD_RESOURCES_ID,
354                 ActionResourceIdService.PERMISSION_MANAGE_ADVANCED_PARAMETERS, (User) getUser( ) );
355 
356         Map<String, Object> model = new HashMap<>( );
357 
358         model.put( MARK_PAGINATOR, paginator );
359         model.put( MARK_NB_ITEMS_PER_PAGE, WorkflowUtils.EMPTY_STRING + _nItemsPerPageWorkflow );
360         model.put( MARK_USER_WORKGROUP_REF_LIST, AdminWorkgroupService.getUserWorkgroups( getUser( ), getLocale( ) ) );
361         model.put( MARK_USER_WORKGROUP_SELECTED, _strWorkGroup );
362         model.put( MARK_ACTIVE_REF_LIST, getRefListActive( getLocale( ) ) );
363         model.put( MARK_ACTIVE_SELECTED, _nIsEnabled );
364         model.put( MARK_WORKFLOW_LIST, paginator.getPageItems( ) );
365         model.put( MARK_PERMISSION_MANAGE_ADVANCED_PARAMETERS, bPermissionAdvancedParameter );
366         model.put( SecurityTokenService.MARK_TOKEN , SecurityTokenService.getInstance( ).getToken( request, WorkflowUtils.CONSTANT_ACTION_MODIFY_WORKFLOW ) );
367 
368         setPageTitleProperty( PROPERTY_MANAGE_WORKFLOW_PAGE_TITLE );
369 
370         HtmlTemplate templateList = AppTemplateService.getTemplate( TEMPLATE_MANAGE_WORKFLOW, getLocale( ), model );
371 
372         return getAdminPage( templateList.getHtml( ) );
373     }
374 
375     /**
376      * Gets the workflow creation page
377      * 
378      * @param request
379      *            The HTTP request
380      * @throws AccessDeniedException
381      *             the {@link AccessDeniedException}
382      * @return The workflow creation page
383      */
384     public String getCreateWorkflow( HttpServletRequest request ) throws AccessDeniedException
385     {
386         AdminUser adminUser = getUser( );
387         Locale locale = getLocale( );
388 
389         Map<String, Object> model = new HashMap<>( );
390         model.put( MARK_USER_WORKGROUP_REF_LIST, AdminWorkgroupService.getUserWorkgroups( adminUser, locale ) );
391         model.put( MARK_DEFAULT_VALUE_WORKGROUP_KEY, AdminWorkgroupService.ALL_GROUPS );
392         model.put( SecurityTokenService.MARK_TOKEN , SecurityTokenService.getInstance( ).getToken( request, TEMPLATE_CREATE_WORKFLOW ) );
393         setPageTitleProperty( PROPERTY_CREATE_WORKFLOW_PAGE_TITLE );
394 
395         HtmlTemplate template = AppTemplateService.getTemplate( TEMPLATE_CREATE_WORKFLOW, locale, model );
396 
397         return getAdminPage( template.getHtml( ) );
398     }
399 
400     /**
401      * Perform the workflow creation
402      * 
403      * @param request
404      *            The HTTP request
405      * @throws AccessDeniedException
406      *             the {@link AccessDeniedException}
407      * @return The URL to go after performing the action
408      */
409     public String doCreateWorkflow( HttpServletRequest request ) throws AccessDeniedException
410     {
411         // Control the validity of the CSRF Token
412         if ( !SecurityTokenService.getInstance( ).validate( request, TEMPLATE_CREATE_WORKFLOW ) )
413         {
414             throw new AccessDeniedException( I18nService.getLocalizedString( WorkflowUtils.MESSAGE_ERROR_INVALID_SECURITY_TOKEN, getLocale( ) ) );
415         }
416 
417         if ( ( request.getParameter( PARAMETER_CANCEL ) == null ) )
418         {
419             Workflow workflow = new Workflow( );
420             String strError = getWorkflowData( request, workflow );
421 
422             if ( strError != null )
423             {
424                 return strError;
425             }
426 
427             workflow.setUid( UUID.randomUUID( ).toString( ) );
428             workflow.setCreationDate( WorkflowUtils.getCurrentTimestamp( ) );
429             _workflowService.create( workflow );
430         }
431 
432         return getJspManageWorkflow( request );
433     }
434 
435     /**
436      * Gets the workflow creation page
437      * 
438      * @param request
439      *            The HTTP request
440      * @throws AccessDeniedException
441      *             the {@link AccessDeniedException}
442      * @return The workflow creation page
443      */
444     public String getModifyWorkflow( HttpServletRequest request ) throws AccessDeniedException
445     {
446         AdminUser adminUser = getUser( );
447         String strIdWorkflow = request.getParameter( PARAMETER_ID_WORKFLOW );
448         String strPane = request.getParameter( PARAMETER_PANE );
449         String strShowTasks = request.getParameter( PARAMETER_SHOW_TASKS );
450         int nIdWorkflow = WorkflowUtils.convertStringToInt( strIdWorkflow );
451         Workflow workflow = null;
452 
453         if ( nIdWorkflow != WorkflowUtils.CONSTANT_ID_NULL )
454         {
455             workflow = _workflowService.findByPrimaryKey( nIdWorkflow );
456         }
457 
458         if ( workflow == null )
459         {
460             throw new AccessDeniedException( LOG_WORKFLOW_NOT_FOUND + nIdWorkflow );
461         }
462 
463         if ( strPane == null )
464         {
465             strPane = PANE_DEFAULT;
466         }
467 
468         StateFilter stateFilter = new StateFilter( );
469         stateFilter.setIdWorkflow( nIdWorkflow );
470 
471         List<State> listState = _stateService.getListStateByFilter( stateFilter );
472 
473         _strCurrentPageIndexState = AbstractPaginator.getPageIndex( request, PARAMETER_PAGE_INDEX_STATE, _strCurrentPageIndexState );
474         _nItemsPerPageState = AbstractPaginator.getItemsPerPage( request, PARAMETER_ITEMS_PER_PAGE_STATE, _nItemsPerPageState, _nDefaultItemsPerPage );
475 
476         LocalizedPaginator<State> paginatorState = new LocalizedPaginator<>( listState, _nItemsPerPageState,
477                 getJspModifyWorkflow( request, nIdWorkflow, MARK_PANE_STATE ), PARAMETER_PAGE_INDEX_STATE, _strCurrentPageIndexState,
478                 PARAMETER_ITEMS_PER_PAGE_STATE, getLocale( ) );
479 
480         ActionFilter actionFilter = new ActionFilter( );
481         actionFilter.setAutomaticReflexiveAction( false );
482         actionFilter.setIdWorkflow( nIdWorkflow );
483 
484         List<Action> listAction = _actionService.getListActionByFilter( actionFilter );
485 
486         for ( Action action : listAction )
487         {
488             action.setStateAfter( _stateService.findByPrimaryKey( action.getStateAfter( ).getId( ) ) );
489             if ( strShowTasks != null )
490             {
491                 List<ITask> listTasks = _taskService.getListTaskByIdAction( action.getId( ), getLocale( ) );               
492                 action.setAllTasks( listTasks );
493             }
494         }
495 
496         _strCurrentPageIndexAction = AbstractPaginator.getPageIndex( request, PARAMETER_PAGE_INDEX_ACTION, _strCurrentPageIndexAction );
497 
498         int nOldItemsPerPageAction = _nItemsPerPageAction;
499         _nItemsPerPageAction = AbstractPaginator.getItemsPerPage( request, PARAMETER_ITEMS_PER_PAGE_ACTION, _nItemsPerPageAction, _nDefaultItemsPerPage );
500 
501         // Boolean that indicates if the action table or the state table should
502         // be displayed
503         if ( ( nOldItemsPerPageAction != _nItemsPerPageAction ) && ( nOldItemsPerPageAction > 0 ) )
504         {
505             strPane = PANE_ACTIONS;
506         }
507 
508         LocalizedPaginator<Action> paginatorAction = new LocalizedPaginator<>( listAction, _nItemsPerPageAction,
509                 getJspModifyWorkflow( request, nIdWorkflow, MARK_PANE_ACTIONS ), PARAMETER_PAGE_INDEX_ACTION, _strCurrentPageIndexAction,
510                 PARAMETER_ITEMS_PER_PAGE_ACTION, getLocale( ) );
511 
512         workflow.setAllActions( paginatorAction.getPageItems( ) );
513         workflow.setAllStates( paginatorState.getPageItems( ) );
514 
515         Map<String, Object> model = new HashMap<>( );
516         model.put( MARK_USER_WORKGROUP_REF_LIST, AdminWorkgroupService.getUserWorkgroups( adminUser, getLocale( ) ) );
517         model.put( MARK_WORKFLOW, workflow );
518         model.put( MARK_PAGINATOR_STATE, paginatorState );
519         model.put( MARK_PAGINATOR_ACTION, paginatorAction );
520         model.put( MARK_STATE_LIST, paginatorState.getPageItems( ) );
521         model.put( MARK_ACTION_LIST, paginatorAction.getPageItems( ) );
522         model.put( MARK_NUMBER_STATE, listState.size( ) );
523         model.put( MARK_NUMBER_ACTION, listAction.size( ) );
524         model.put( MARK_NB_ITEMS_PER_PAGE_STATE, WorkflowUtils.EMPTY_STRING + _nItemsPerPageState );
525         model.put( MARK_NB_ITEMS_PER_PAGE_ACTION, WorkflowUtils.EMPTY_STRING + _nItemsPerPageAction );
526         model.put( MARK_PANE, strPane );
527         
528         Map<String,String> mapStateBeforeName = new HashMap<>( );
529         for (Action actionBefore : paginatorAction.getPageItems( ) )
530         {
531         	for (Integer nStateBefore : actionBefore.getListIdStateBefore( ) )
532         	{
533         		mapStateBeforeName.put(String.valueOf(nStateBefore), _stateService.findByPrimaryKey( nStateBefore ).getName( ) );
534         	}
535         }
536         
537         model.put(MARK_STATE_BEFORE_MAP, mapStateBeforeName);
538         
539         if ( strShowTasks != null )
540         {
541             model.put( MARK_SHOW_TASKS, "true" );
542         }
543         model.put( MARK_MDGRAPH, WorkflowGraphExportService.generate( workflow, AppPathService.getBaseUrl( request ) ) );
544         // Add CSRF Token
545         model.put( SecurityTokenService.MARK_TOKEN , SecurityTokenService.getInstance( ).getToken( request, TEMPLATE_MODIFY_WORKFLOW ) );
546 
547         setPageTitleProperty( PROPERTY_MODIFY_WORKFLOW_PAGE_TITLE );
548 
549         HtmlTemplate template = AppTemplateService.getTemplate( TEMPLATE_MODIFY_WORKFLOW, getLocale( ), model );
550 
551         return getAdminPage( template.getHtml( ) );
552     }
553 
554     /**
555      * Perform the workflow modification
556      * 
557      * @param request
558      *            The HTTP request
559      * @throws AccessDeniedException
560      *             the {@link AccessDeniedException}
561      * @return The URL to go after performing the action
562      */
563     public String doModifyWorkflow( HttpServletRequest request ) throws AccessDeniedException
564     {
565         // Control the validity of the CSRF Token
566         if ( !SecurityTokenService.getInstance( ).validate( request, TEMPLATE_MODIFY_WORKFLOW ) )
567         {
568             throw new AccessDeniedException( I18nService.getLocalizedString( WorkflowUtils.MESSAGE_ERROR_INVALID_SECURITY_TOKEN, getLocale( ) ) );
569         }
570 
571         if ( request.getParameter( PARAMETER_CANCEL ) == null )
572         {
573             String strIdWorkflow = request.getParameter( PARAMETER_ID_WORKFLOW );
574             int nIdWorkflow = WorkflowUtils.convertStringToInt( strIdWorkflow );
575             Workflow workflow = null;
576 
577             if ( nIdWorkflow != WorkflowUtils.CONSTANT_ID_NULL )
578             {
579                 workflow = _workflowService.findByPrimaryKey( nIdWorkflow );
580 
581                 if ( ( workflow == null ) )
582                 {
583                     throw new AccessDeniedException( LOG_WORKFLOW_NOT_FOUND + nIdWorkflow );
584                 }
585 
586                 String strError = getWorkflowData( request, workflow );
587 
588                 if ( strError != null )
589                 {
590                     return strError;
591                 }
592 
593                 _workflowService.update( workflow );
594 
595                 if ( request.getParameter( PARAMETER_APPLY ) != null )
596                 {
597                     return getJspModifyWorkflow( request, nIdWorkflow );
598                 }
599             }
600         }
601 
602         return getJspManageWorkflow( request );
603     }
604 
605     /**
606      * Gets the confirmation page of remove all Directory Record
607      * 
608      * @param request
609      *            The HTTP request
610      * @throws AccessDeniedException
611      *             the {@link AccessDeniedException}
612      * @return the confirmation page of delete all Directory Record
613      */
614     public String getConfirmRemoveWorkflow( HttpServletRequest request ) throws AccessDeniedException
615     {
616         String strIdWorkflow = request.getParameter( PARAMETER_ID_WORKFLOW );
617 
618         UrlItem url = new UrlItem( JSP_DO_REMOVE_WORKFLOW );
619         url.addParameter( PARAMETER_ID_WORKFLOW, strIdWorkflow );
620         url.addParameter( SecurityTokenService.PARAMETER_TOKEN, SecurityTokenService.getInstance( ).getToken( request, JSP_DO_REMOVE_WORKFLOW ) );
621 
622         return AdminMessageService.getMessageUrl( request, MESSAGE_CONFIRM_REMOVE_WORKFLOW, url.getUrl( ), AdminMessage.TYPE_CONFIRMATION );
623     }
624 
625     /**
626      * Remove all workflow record of the workflow
627      * 
628      * @param request
629      *            The HTTP request
630      * @throws AccessDeniedException
631      *             the {@link AccessDeniedException}
632      * @return The URL to go after performing the action
633      */
634     public String doRemoveWorkflow( HttpServletRequest request ) throws AccessDeniedException
635     {
636         // Control the validity of the CSRF Token
637         if ( !SecurityTokenService.getInstance( ).validate( request, JSP_DO_REMOVE_WORKFLOW ) )
638         {
639             throw new AccessDeniedException( I18nService.getLocalizedString( WorkflowUtils.MESSAGE_ERROR_INVALID_SECURITY_TOKEN, getLocale( ) ) );
640         }
641 
642         String strIdWorkflow = request.getParameter( PARAMETER_ID_WORKFLOW );
643 
644         int nIdWorkflow = WorkflowUtils.convertStringToInt( strIdWorkflow );
645 
646         ArrayList<String> listErrors = new ArrayList<>( );
647 
648         if ( !WorkflowRemovalListenerService.getService( ).checkForRemoval( strIdWorkflow, listErrors, getLocale( ) ) )
649         {
650             String strCause = AdminMessageService.getFormattedList( listErrors, getLocale( ) );
651             Object [ ] args = {
652                     strCause
653             };
654 
655             return AdminMessageService.getMessageUrl( request, MESSAGE_CAN_NOT_REMOVE_WORKFLOW, args, AdminMessage.TYPE_STOP );
656         }
657 
658         _workflowService.remove( nIdWorkflow );
659 
660         return getJspManageWorkflow( request );
661     }
662 
663     /**
664      * Remove all workflow record of the workflow
665      * 
666      * @param request
667      *            The HTTP request
668      * @throws AccessDeniedException
669      *             the {@link AccessDeniedException}
670      * @return The URL to go after performing the action
671      */
672     public String doEnableWorkflow( HttpServletRequest request ) throws AccessDeniedException
673     {
674         // Control the validity of the CSRF Token
675         if ( !SecurityTokenService.getInstance( ).validate( request, WorkflowUtils.CONSTANT_ACTION_MODIFY_WORKFLOW ) )
676         {
677             throw new AccessDeniedException( I18nService.getLocalizedString( WorkflowUtils.MESSAGE_ERROR_INVALID_SECURITY_TOKEN, getLocale( ) ) );
678         }
679 
680         String strIdWorkflow = request.getParameter( PARAMETER_ID_WORKFLOW );
681         int nIdWorkflow = WorkflowUtils.convertStringToInt( strIdWorkflow );
682         Workflow workflow = _workflowService.findByPrimaryKey( nIdWorkflow );
683 
684         if ( workflow == null )
685         {
686             throw new AccessDeniedException( LOG_WORKFLOW_NOT_FOUND + nIdWorkflow );
687         }
688 
689         workflow.setEnabled( true );
690         _workflowService.update( workflow );
691 
692         return getJspManageWorkflow( request );
693     }
694 
695     /**
696      * Remove all workflow record of the workflow
697      * 
698      * @param request
699      *            The HTTP request
700      * @throws AccessDeniedException
701      *             the {@link AccessDeniedException}
702      * @return The URL to go after performing the action
703      */
704     public String doDisableWorkflow( HttpServletRequest request ) throws AccessDeniedException
705     {
706         // Control the validity of the CSRF Token
707         if ( !SecurityTokenService.getInstance( ).validate( request, WorkflowUtils.CONSTANT_ACTION_MODIFY_WORKFLOW ) )
708         {
709             throw new AccessDeniedException( I18nService.getLocalizedString( WorkflowUtils.MESSAGE_ERROR_INVALID_SECURITY_TOKEN, getLocale( ) ) );
710         }
711 
712         String strIdWorkflow = request.getParameter( PARAMETER_ID_WORKFLOW );
713         int nIdWorkflow = WorkflowUtils.convertStringToInt( strIdWorkflow );
714         Workflow workflow = _workflowService.findByPrimaryKey( nIdWorkflow );
715         ArrayList<String> listErrors = new ArrayList<>( );
716 
717         if ( workflow == null )
718         {
719             throw new AccessDeniedException( LOG_WORKFLOW_NOT_FOUND + nIdWorkflow );
720         }
721 
722         if ( !WorkflowRemovalListenerService.getService( ).checkForRemoval( strIdWorkflow, listErrors, getLocale( ) ) )
723         {
724             String strCause = AdminMessageService.getFormattedList( listErrors, getLocale( ) );
725             Object [ ] args = {
726                     strCause
727             };
728 
729             return AdminMessageService.getMessageUrl( request, MESSAGE_CAN_NOT_DISABLE_WORKFLOW, args, AdminMessage.TYPE_STOP );
730         }
731 
732         workflow.setEnabled( false );
733         _workflowService.update( workflow );
734 
735         return getJspManageWorkflow( request );
736     }
737 
738     /**
739      * set the data of the workflow in the workflow object
740      * 
741      * @param request
742      *            The HTTP request
743      * @param workflow
744      *            the workflow object
745      * @param locale
746      *            the locale
747      * @return null if no error appear
748      */
749     private String getWorkflowData( HttpServletRequest request, Workflow workflow )
750     {
751         String strName = request.getParameter( PARAMETER_NAME );
752         String strDescription = request.getParameter( PARAMETER_DESCRIPTION );
753 
754         String strWorkgroup = request.getParameter( PARAMETER_WORKGROUP );
755         String strFieldError = WorkflowUtils.EMPTY_STRING;
756 
757         if ( ( strName == null ) || strName.trim( ).equals( WorkflowUtils.EMPTY_STRING ) )
758         {
759             strFieldError = FIELD_WORKFLOW_NAME;
760         }
761         else
762             if ( ( strDescription == null ) || strDescription.trim( ).equals( WorkflowUtils.EMPTY_STRING ) )
763             {
764                 strFieldError = FIELD_WORKFLOW_DESCRIPTION;
765             }
766 
767         if ( !strFieldError.equals( WorkflowUtils.EMPTY_STRING ) )
768         {
769             Object [ ] tabRequiredFields = {
770                     I18nService.getLocalizedString( strFieldError, getLocale( ) )
771             };
772 
773             return AdminMessageService.getMessageUrl( request, MESSAGE_MANDATORY_FIELD, tabRequiredFields, AdminMessage.TYPE_STOP );
774         }
775 
776         workflow.setName( strName );
777         workflow.setDescription( strDescription );
778         workflow.setWorkgroup( strWorkgroup );
779 
780         return null;
781     }
782 
783     /**
784      * Gets the workflow creation page
785      * 
786      * @param request
787      *            The HTTP request
788      * @throws AccessDeniedException
789      *             the {@link AccessDeniedException}
790      * @return The workflow creation page
791      */
792     public String getCreateState( HttpServletRequest request ) throws AccessDeniedException
793     {
794         String strIdWorkflow = request.getParameter( PARAMETER_ID_WORKFLOW );
795         int nIdWorkflow = WorkflowUtils.convertStringToInt( strIdWorkflow );
796         Workflow workflow = null;
797 
798         if ( nIdWorkflow != WorkflowUtils.CONSTANT_ID_NULL )
799         {
800             workflow = _workflowService.findByPrimaryKey( nIdWorkflow );
801         }
802 
803         if ( workflow == null )
804         {
805             throw new AccessDeniedException( LOG_WORKFLOW_NOT_FOUND + nIdWorkflow );
806         }
807 
808         List<Icon> listIcon = _iconService.getListIcons( );
809 
810         Map<String, Object> model = new HashMap<>( );
811         model.put( MARK_WORKFLOW, workflow );
812         model.put( MARK_INITIAL_STATE, _stateService.getInitialState( nIdWorkflow ) != null );
813         model.put( MARK_ICON_LIST, listIcon );
814         model.put( SecurityTokenService.MARK_TOKEN , SecurityTokenService.getInstance( ).getToken( request, TEMPLATE_CREATE_STATE ) );
815         setPageTitleProperty( PROPERTY_CREATE_STATE_PAGE_TITLE );
816 
817         HtmlTemplate template = AppTemplateService.getTemplate( TEMPLATE_CREATE_STATE, getLocale( ), model );
818 
819         return getAdminPage( template.getHtml( ) );
820     }
821 
822     /**
823      * Perform the workflow creation
824      * 
825      * @param request
826      *            The HTTP request
827      * @throws AccessDeniedException
828      *             the {@link AccessDeniedException}
829      * @return The URL to go after performing the action
830      */
831     public String doCreateState( HttpServletRequest request ) throws AccessDeniedException
832     {
833         // Control the validity of the CSRF Token
834         if ( !SecurityTokenService.getInstance( ).validate( request, TEMPLATE_CREATE_STATE ) )
835         {
836             throw new AccessDeniedException( I18nService.getLocalizedString( WorkflowUtils.MESSAGE_ERROR_INVALID_SECURITY_TOKEN, getLocale( ) ) );
837         }
838 
839         String strIdWorkflow = request.getParameter( PARAMETER_ID_WORKFLOW );
840         int nIdWorkflow = WorkflowUtils.convertStringToInt( strIdWorkflow );
841 
842         if ( ( request.getParameter( PARAMETER_CANCEL ) == null ) )
843         {
844             Workflow workflow = null;
845 
846             if ( nIdWorkflow != WorkflowUtils.CONSTANT_ID_NULL )
847             {
848                 workflow = _workflowService.findByPrimaryKey( nIdWorkflow );
849             }
850 
851             if ( workflow == null )
852             {
853                 throw new AccessDeniedException( LOG_WORKFLOW_NOT_FOUND + nIdWorkflow );
854             }
855 
856             State state = new State( );
857             state.setUid( UUID.randomUUID( ).toString( ) );
858             state.setWorkflow( workflow );
859 
860             String strError = getStateData( request, state );
861 
862             if ( strError != null )
863             {
864                 return strError;
865             }
866 
867             if ( Boolean.TRUE.equals( state.isInitialState( ) ) )
868             {
869                 // test if initial test already exist
870                 State stateInitial = _stateService.getInitialState( nIdWorkflow );
871 
872                 if ( stateInitial != null )
873                 {
874                     Object [ ] tabInitialState = {
875                             stateInitial.getName( )
876                     };
877 
878                     return AdminMessageService.getMessageUrl( request, MESSAGE_INITIAL_STATE_ALREADY_EXIST, tabInitialState, AdminMessage.TYPE_STOP );
879                 }
880             }
881 
882             // get the maximum order number in this workflow and set max+1
883             int nMaximumOrder = _stateService.findMaximumOrderByWorkflowId( nIdWorkflow );
884             state.setOrder( nMaximumOrder + 1 );
885 
886             _stateService.create( state );
887         }
888 
889         return getJspModifyWorkflow( request, nIdWorkflow );
890     }
891 
892     /**
893      * Gets the workflow creation page
894      * 
895      * @param request
896      *            The HTTP request
897      * @throws AccessDeniedException
898      *             the {@link AccessDeniedException}
899      * @return The workflow creation page
900      */
901     public String getModifyState( HttpServletRequest request ) throws AccessDeniedException
902     {
903         String strIdState = request.getParameter( PARAMETER_ID_STATE );
904         int nIdState = WorkflowUtils.convertStringToInt( strIdState );
905         State state = null;
906 
907         if ( nIdState != WorkflowUtils.CONSTANT_ID_NULL )
908         {
909             state = _stateService.findByPrimaryKey( nIdState );
910         }
911 
912         if ( state == null )
913         {
914             throw new AccessDeniedException( "State not found for ID " + nIdState );
915         }
916 
917         List<Icon> listIcon = _iconService.getListIcons( );
918         
919         if( state.getUid() == null ) {
920         	state.setUid( UUID.randomUUID( ).toString( ) );
921         }
922 
923         Map<String, Object> model = new HashMap<>( );
924         model.put( MARK_STATE, state );
925         model.put( MARK_ICON_LIST, listIcon );
926         model.put( SecurityTokenService.MARK_TOKEN , SecurityTokenService.getInstance( ).getToken( request, TEMPLATE_MODIFY_STATE ) );
927 
928         setPageTitleProperty( PROPERTY_MODIFY_STATE_PAGE_TITLE );
929 
930         HtmlTemplate template = AppTemplateService.getTemplate( TEMPLATE_MODIFY_STATE, getLocale( ), model );
931 
932         return getAdminPage( template.getHtml( ) );
933     }
934 
935     /**
936      * Perform the workflow modification
937      * 
938      * @param request
939      *            The HTTP request
940      * @throws AccessDeniedException
941      *             the {@link AccessDeniedException}
942      * @return The URL to go after performing the action
943      */
944     public String doModifyState( HttpServletRequest request ) throws AccessDeniedException
945     {
946         // Control the validity of the CSRF Token
947         if ( !SecurityTokenService.getInstance( ).validate( request, TEMPLATE_MODIFY_STATE ) )
948         {
949             throw new AccessDeniedException( I18nService.getLocalizedString( WorkflowUtils.MESSAGE_ERROR_INVALID_SECURITY_TOKEN, getLocale( ) ) );
950         }
951 
952         String strIdState = request.getParameter( PARAMETER_ID_STATE );
953         int nIdState = WorkflowUtils.convertStringToInt( strIdState );
954         State state = null;
955 
956         if ( nIdState != WorkflowUtils.CONSTANT_ID_NULL )
957         {
958             state = _stateService.findByPrimaryKey( nIdState );
959         }
960 
961         if ( state == null )
962         {
963             throw new AccessDeniedException( "State not found for ID " + nIdState );
964         }
965 
966         if ( request.getParameter( PARAMETER_CANCEL ) == null )
967         {
968             boolean isInitialTestStore = state.isInitialState( );
969             String strError = getStateData( request, state );
970 
971             if ( strError != null )
972             {
973                 return strError;
974             }
975 
976             if ( !isInitialTestStore && Boolean.TRUE.equals( state.isInitialState( ) ) )
977             {
978                 // test if initial test already exist
979                 StateFilter filter = new StateFilter( );
980                 filter.setIdWorkflow( state.getWorkflow( ).getId( ) );
981                 filter.setIsInitialState( StateFilter.FILTER_TRUE );
982 
983                 List<State> listState = _stateService.getListStateByFilter( filter );
984 
985                 if ( CollectionUtils.isNotEmpty( listState ) )
986                 {
987                     Object [ ] tabInitialState = {
988                             listState.get( 0 ).getName( )
989                     };
990 
991                     return AdminMessageService.getMessageUrl( request, MESSAGE_INITIAL_STATE_ALREADY_EXIST, tabInitialState, AdminMessage.TYPE_STOP );
992                 }
993             }
994 
995             _stateService.update( state );
996         }
997 
998         return getJspModifyWorkflow( request, state.getWorkflow( ).getId( ) );
999     }
1000 
1001     /**
1002      * Gets the confirmation page of remove all Directory Record
1003      * 
1004      * @param request
1005      *            The HTTP request
1006      * @throws AccessDeniedException
1007      *             the {@link AccessDeniedException}
1008      * @return the confirmation page of delete all Directory Record
1009      */
1010     public String getConfirmRemoveState( HttpServletRequest request ) throws AccessDeniedException
1011     {
1012         String strIdState = request.getParameter( PARAMETER_ID_STATE );
1013         int nIdState = WorkflowUtils.convertStringToInt( strIdState );
1014 
1015         ActionFilter filter = new ActionFilter( );
1016         filter.setIdStateBefore( nIdState );
1017         filter.setAutomaticReflexiveAction( false );
1018 
1019         List<Action> listActionStateBefore = _actionService.getListActionByFilter( filter );
1020         filter.setIdStateBefore( ActionFilter.ALL_INT );
1021         filter.setIdStateAfter( nIdState );
1022 
1023         List<Action> listActionStateAfter = _actionService.getListActionByFilter( filter );
1024 
1025         if ( CollectionUtils.isNotEmpty( listActionStateBefore ) || CollectionUtils.isNotEmpty( listActionStateAfter ) )
1026         {
1027             return AdminMessageService.getMessageUrl( request, MESSAGE_CAN_NOT_REMOVE_STATE_ACTIONS_ARE_ASSOCIATE, AdminMessage.TYPE_STOP );
1028         }
1029 
1030         UrlItem url = new UrlItem( JSP_DO_REMOVE_STATE );
1031         url.addParameter( PARAMETER_ID_STATE, strIdState );
1032         url.addParameter( SecurityTokenService.PARAMETER_TOKEN, SecurityTokenService.getInstance( ).getToken( request, JSP_DO_REMOVE_STATE ) );
1033 
1034         return AdminMessageService.getMessageUrl( request, MESSAGE_CONFIRM_REMOVE_STATE, url.getUrl( ), AdminMessage.TYPE_CONFIRMATION );
1035     }
1036 
1037     /**
1038      * Remove all workflow record of the workflow
1039      * 
1040      * @param request
1041      *            The HTTP request
1042      * @throws AccessDeniedException
1043      *             the {@link AccessDeniedException}
1044      * @return The URL to go after performing the action
1045      */
1046     public String doRemoveState( HttpServletRequest request ) throws AccessDeniedException
1047     {
1048         // Control the validity of the CSRF Token
1049         if ( !SecurityTokenService.getInstance( ).validate( request, JSP_DO_REMOVE_STATE ) )
1050         {
1051             throw new AccessDeniedException( I18nService.getLocalizedString( WorkflowUtils.MESSAGE_ERROR_INVALID_SECURITY_TOKEN, getLocale( ) ) );
1052         }
1053 
1054         String strIdState = request.getParameter( PARAMETER_ID_STATE );
1055         int nIdState = WorkflowUtils.convertStringToInt( strIdState );
1056 
1057         ActionFilter filter = new ActionFilter( );
1058         filter.setAutomaticReflexiveAction( false );
1059         filter.setIdStateBefore( nIdState );
1060 
1061         List<Action> listActionStateBefore = _actionService.getListActionByFilter( filter );
1062         filter.setIdStateBefore( ActionFilter.ALL_INT );
1063         filter.setIdStateAfter( nIdState );
1064 
1065         List<Action> listActionStateAfter = _actionService.getListActionByFilter( filter );
1066 
1067         if ( CollectionUtils.isNotEmpty( listActionStateBefore ) || CollectionUtils.isNotEmpty( listActionStateAfter ) )
1068         {
1069             return AdminMessageService.getMessageUrl( request, MESSAGE_CAN_NOT_REMOVE_STATE_ACTIONS_ARE_ASSOCIATE, AdminMessage.TYPE_STOP );
1070         }
1071 
1072         State state = _stateService.findByPrimaryKey( nIdState );
1073 
1074         if ( state != null )
1075         {
1076             List<Action> listActions = getAutomaticReflexiveActionsFromState( nIdState );
1077 
1078             if ( CollectionUtils.isNotEmpty( listActions ) )
1079             {
1080                 for ( Action action : listActions )
1081                 {
1082                     List<ITask> listTasksFound = _taskService.getListTaskByIdAction( action.getId( ), getLocale( ) );
1083 
1084                     if ( CollectionUtils.isNotEmpty( listTasksFound ) )
1085                     {
1086                         return AdminMessageService.getMessageUrl( request, MESSAGE_CAN_NOT_REMOVE_STATE_TASKS_ARE_ASSOCIATE, AdminMessage.TYPE_STOP );
1087                     }
1088                 }
1089             }
1090 
1091             _stateService.remove( nIdState );
1092             _stateService.decrementOrderByOne( state.getOrder( ), state.getWorkflow( ).getId( ) );
1093 
1094             return getJspModifyWorkflow( request, state.getWorkflow( ).getId( ) );
1095         }
1096 
1097         return getJspManageWorkflow( request );
1098     }
1099 
1100     /**
1101      * set the data of the state in the state object
1102      * 
1103      * @param request
1104      *            The HTTP request
1105      * @param state
1106      *            the state object
1107      * @param locale
1108      *            the locale
1109      * @return null if no error appear
1110      */
1111     private String getStateData( HttpServletRequest request, State state )
1112     {
1113         String strName = request.getParameter( PARAMETER_NAME );
1114         String strDescription = request.getParameter( PARAMETER_DESCRIPTION );
1115         String strIsInitialState = request.getParameter( PARAMETER_IS_INITIAL_STATE );
1116         String strIsRequiredWorkgroupAssigned = request.getParameter( PARAMETER_IS_REQUIRED_WORKGROUP_ASSIGNED );
1117         String strIdIcon = request.getParameter( PARAMETER_ID_ICON );
1118 
1119         String strFieldError = WorkflowUtils.EMPTY_STRING;
1120 
1121         if ( ( strName == null ) || strName.trim( ).equals( WorkflowUtils.EMPTY_STRING ) )
1122         {
1123             strFieldError = FIELD_STATE_NAME;
1124         }
1125         else
1126             if ( ( strDescription == null ) || strDescription.trim( ).equals( WorkflowUtils.EMPTY_STRING ) )
1127             {
1128                 strFieldError = FIELD_STATE_DESCRIPTION;
1129             }
1130 
1131         if ( !strFieldError.equals( WorkflowUtils.EMPTY_STRING ) )
1132         {
1133             Object [ ] tabRequiredFields = {
1134                     I18nService.getLocalizedString( strFieldError, getLocale( ) )
1135             };
1136 
1137             return AdminMessageService.getMessageUrl( request, MESSAGE_MANDATORY_FIELD, tabRequiredFields, AdminMessage.TYPE_STOP );
1138         }
1139 
1140         int nIdIcon = WorkflowUtils.convertStringToInt( strIdIcon );
1141 
1142         state.setName( strName );
1143         state.setDescription( strDescription );
1144         state.setInitialState( strIsInitialState != null );
1145         state.setRequiredWorkgroupAssigned( strIsRequiredWorkgroupAssigned != null );
1146 
1147         Icon icon = new Icon( );
1148         icon.setId( nIdIcon );
1149         state.setIcon( icon );
1150 
1151         return null;
1152     }
1153 
1154     /**
1155      * Gets the workflow creation page
1156      * 
1157      * @param request
1158      *            The HTTP request
1159      * @throws AccessDeniedException
1160      *             the {@link AccessDeniedException}
1161      * @return The workflow creation page
1162      */
1163     public String getCreateAction( HttpServletRequest request ) throws AccessDeniedException
1164     {
1165         String strIdWorkflow = request.getParameter( PARAMETER_ID_WORKFLOW );
1166         int nIdWorkflow = WorkflowUtils.convertStringToInt( strIdWorkflow );
1167         Workflow workflow = null;
1168 
1169         if ( nIdWorkflow != WorkflowUtils.CONSTANT_ID_NULL )
1170         {
1171             workflow = _workflowService.findByPrimaryKey( nIdWorkflow );
1172         }
1173 
1174         if ( workflow == null )
1175         {
1176             throw new AccessDeniedException( LOG_WORKFLOW_NOT_FOUND + nIdWorkflow );
1177         }
1178 
1179         Map<String, Object> model = new HashMap<>( );
1180 
1181         StateFilter filter = new StateFilter( );
1182         filter.setIdWorkflow( nIdWorkflow );
1183 
1184         List<State> listState = _stateService.getListStateByFilter( filter );
1185         List<Icon> listIcon = _iconService.getListIcons( );
1186 
1187         model.put( MARK_WORKFLOW, workflow );
1188         model.put( MARK_STATE_LIST, WorkflowUtils.getRefList( listState, false, getLocale( ) ) );
1189         model.put( MARK_ALTERNATIVE_STATE_LIST, WorkflowUtils.getRefList( listState, true, getLocale( ) ) );
1190         model.put( MARK_ICON_LIST, listIcon );
1191         model.put( MARK_AVAILABLE_LINKED_ACTIONS, getAvailableActionsToLink( WorkflowUtils.CONSTANT_ID_NULL, nIdWorkflow ) );
1192         model.put( SecurityTokenService.MARK_TOKEN , SecurityTokenService.getInstance( ).getToken( request, TEMPLATE_CREATE_ACTION ) );
1193 
1194         setPageTitleProperty( PROPERTY_CREATE_ACTION_PAGE_TITLE );
1195 
1196         HtmlTemplate template = AppTemplateService.getTemplate( TEMPLATE_CREATE_ACTION, getLocale( ), model );
1197 
1198         return getAdminPage( template.getHtml( ) );
1199     }
1200 
1201     /**
1202      * Perform the workflow creation
1203      * 
1204      * @param request
1205      *            The HTTP request
1206      * @throws AccessDeniedException
1207      *             the {@link AccessDeniedException}
1208      * @return The URL to go after performing the action
1209      */
1210     public String doCreateAction( HttpServletRequest request ) throws AccessDeniedException
1211     {
1212         // Control the validity of the CSRF Token
1213         if ( !SecurityTokenService.getInstance( ).validate( request, TEMPLATE_CREATE_ACTION ) )
1214         {
1215             throw new AccessDeniedException( I18nService.getLocalizedString( WorkflowUtils.MESSAGE_ERROR_INVALID_SECURITY_TOKEN, getLocale( ) ) );
1216         }
1217 
1218         String strIdWorkflow = request.getParameter( PARAMETER_ID_WORKFLOW );
1219         int nIdWorkflow = WorkflowUtils.convertStringToInt( strIdWorkflow );
1220 
1221         if ( ( request.getParameter( PARAMETER_CANCEL ) == null ) )
1222         {
1223             Workflow workflow = null;
1224 
1225             if ( nIdWorkflow != WorkflowUtils.CONSTANT_ID_NULL )
1226             {
1227                 workflow = _workflowService.findByPrimaryKey( nIdWorkflow );
1228             }
1229 
1230             if ( workflow == null )
1231             {
1232                 throw new AccessDeniedException( LOG_WORKFLOW_NOT_FOUND + nIdWorkflow );
1233             }
1234 
1235             Action action = new Action( );
1236             action.setUid( UUID.randomUUID( ).toString( ) );
1237             action.setWorkflow( workflow );
1238 
1239             String strError = getActionData( request, action );
1240 
1241             if ( strError != null )
1242             {
1243                 return strError;
1244             }
1245 
1246             // get the maximum order number in this workflow and set max+1
1247             int nMaximumOrder = _actionService.findMaximumOrderByWorkflowId( nIdWorkflow );
1248             action.setOrder( nMaximumOrder + 1 );
1249 
1250             _actionService.create( action );
1251 
1252             if ( request.getParameter( PARAMETER_APPLY ) != null )
1253             {
1254                 return getJspModifyAction( request, action.getId( ) );
1255             }
1256         }
1257 
1258         return getJspModifyWorkflow( request, nIdWorkflow, PANE_ACTIONS );
1259     }
1260 
1261     /**
1262      * set the data of the action in the action object
1263      * 
1264      * @param request
1265      *            The HTTP request
1266      * @param action
1267      *            the action object
1268      * @param locale
1269      *            the locale
1270      * @return null if no error appear
1271      */
1272     private String getActionData( HttpServletRequest request, Action action )
1273     {
1274         String strName = request.getParameter( PARAMETER_NAME );
1275         String strDescription = request.getParameter( PARAMETER_DESCRIPTION );
1276         String[] strTableIdStateBefore = request.getParameterValues(PARAMETER_ID_STATE_BEFORE);
1277         String strIdStateAfter = request.getParameter( PARAMETER_ID_STATE_AFTER );
1278         String strIdAlternativeStateAfter = request.getParameter( PARAMETER_ID_ALTERNATIVE_STATE_AFTER );
1279         String strIdIcon = request.getParameter( PARAMETER_ID_ICON );
1280         String strAutomatic = request.getParameter( PARAMETER_ID_AUTOMATIC );
1281         String strIsMassAction = request.getParameter( PARAMETER_IS_MASS_ACTION );
1282 
1283         int nIdStateAfter = WorkflowUtils.convertStringToInt( strIdStateAfter );
1284         int nIdAlternativeStateAfter = WorkflowUtils.convertStringToInt( strIdAlternativeStateAfter );
1285         int nIdIcon = WorkflowUtils.convertStringToInt( strIdIcon );
1286         List<String> lstStrTableIdStateBefore = WorkflowUtils.convertStringArrayToList(strTableIdStateBefore); 
1287         boolean bIsAutomatic = strAutomatic != null;
1288         boolean bIsMassAction = strIsMassAction != null;
1289 
1290         String strFieldError = StringUtils.EMPTY;
1291 
1292         if ( StringUtils.isBlank( strName ) )
1293         {
1294             strFieldError = FIELD_ACTION_NAME;
1295         }
1296         else
1297             if ( StringUtils.isBlank( strDescription ) )
1298             {
1299                 strFieldError = FIELD_ACTION_DESCRIPTION;
1300             }
1301             else
1302             	if ( lstStrTableIdStateBefore.isEmpty( ) )
1303                 {
1304                     strFieldError = FIELD_STATE_BEFORE;
1305                 }
1306                 else
1307                     if ( nIdStateAfter == WorkflowUtils.CONSTANT_ID_NULL )
1308                     {
1309                         strFieldError = FIELD_STATE_AFTER;
1310                     }
1311                     else
1312                         if ( nIdIcon == WorkflowUtils.CONSTANT_ID_NULL )
1313                         {
1314                             strFieldError = FIELD_ICON;
1315                         }
1316                         else
1317                         	if ( bIsAutomatic && ( lstStrTableIdStateBefore.stream( ).anyMatch( x -> WorkflowUtils.convertStringToInt( x ) ==  nIdStateAfter ) ) )
1318                             {
1319                                 Object [ ] tabRequiredFields = {
1320                                         I18nService.getLocalizedString( FIELD_STATE_BEFORE, getLocale( ) ),
1321                                         I18nService.getLocalizedString( FIELD_STATE_AFTER, getLocale( ) ),
1322                                 };
1323 
1324                                 return AdminMessageService.getMessageUrl( request, MESSAGE_ERROR_AUTOMATIC_FIELD, tabRequiredFields, AdminMessage.TYPE_STOP );
1325                             }
1326                             else
1327                                 if ( bIsAutomatic && bIsMassAction )
1328                                 {
1329                                     return AdminMessageService.getMessageUrl( request, MESSAGE_MASS_ACTION_CANNOT_BE_AUTOMATIC, AdminMessage.TYPE_STOP );
1330                                 }
1331 
1332         if ( StringUtils.isNotBlank( strFieldError ) )
1333         {
1334             Object [ ] tabRequiredFields = {
1335                     I18nService.getLocalizedString( strFieldError, getLocale( ) )
1336             };
1337 
1338             return AdminMessageService.getMessageUrl( request, MESSAGE_MANDATORY_FIELD, tabRequiredFields, AdminMessage.TYPE_STOP );
1339         }
1340 
1341         if ( bIsAutomatic )
1342         {
1343             for ( ITask task : _taskService.getListTaskByIdAction( action.getId( ), getLocale( ) ) )
1344             {
1345                 if ( !task.getTaskType( ).isTaskForAutomaticAction( ) )
1346                 {
1347                     return AdminMessageService.getMessageUrl( request, MESSAGE_TASK_IS_NOT_AUTOMATIC, AdminMessage.TYPE_STOP );
1348                 }
1349             }
1350         }
1351 
1352         action.setName( strName );
1353         action.setDescription( strDescription );
1354         
1355         List<Integer> listIdStateBefore = new ArrayList<>();
1356         for (String strStateBefore : lstStrTableIdStateBefore)
1357         {
1358         	int nIdStateBeforeList = WorkflowUtils.convertStringToInt( strStateBefore );
1359         	listIdStateBefore.add( nIdStateBeforeList );
1360         }
1361         action.setListIdStateBefore(listIdStateBefore);
1362 
1363         State stateAfter = new State( );
1364         stateAfter.setId( nIdStateAfter );
1365         action.setStateAfter( stateAfter );
1366         
1367         State alternativeStateAfter = new State( );
1368         alternativeStateAfter.setId( nIdAlternativeStateAfter );
1369         action.setAlternativeStateAfter( alternativeStateAfter );
1370 
1371         Icon icon = new Icon( );
1372         icon.setId( nIdIcon );
1373         action.setIcon( icon );
1374 
1375         action.setAutomaticState( bIsAutomatic );
1376         action.setMassAction( bIsMassAction );
1377 
1378         action.setListIdsLinkedAction( getSelectedLinkedActions( action, request ) );
1379 
1380         return null;
1381     }
1382 
1383     /**
1384      * Gets the workflow creation page
1385      * 
1386      * @param request
1387      *            The HTTP request
1388      * @throws AccessDeniedException
1389      *             the {@link AccessDeniedException}
1390      * @return The workflow creation page
1391      */
1392     public String getModifyAction( HttpServletRequest request ) throws AccessDeniedException
1393     {
1394         String strIdAction = request.getParameter( PARAMETER_ID_ACTION );
1395         int nIdAction = WorkflowUtils.convertStringToInt( strIdAction );
1396         Action action = null;
1397 
1398         if ( nIdAction != WorkflowUtils.CONSTANT_ID_NULL )
1399         {
1400             action = _actionService.findByPrimaryKey( nIdAction );
1401         }
1402 
1403         if ( action == null )
1404         {
1405             throw new AccessDeniedException( LOG_ACTION_NOT_FOUND + nIdAction );
1406         }
1407 
1408         StateFilter filter = new StateFilter( );
1409         filter.setIdWorkflow( action.getWorkflow( ).getId( ) );
1410 
1411         List<State> listState = _stateService.getListStateByFilter( filter );
1412         List<Icon> listIcon = _iconService.getListIcons( );
1413 
1414         ReferenceList refListTaskType = new ReferenceList( );
1415         Collection<ITaskType> taskTypeList = _taskFactory.getAllTaskTypes( );
1416 
1417         List<PrerequisiteDTO> listPrerequisiteDTO = null;
1418         List<Prerequisite> listPrerequisite = _prerequisiteManagementService.getListPrerequisite( action.getId( ) );
1419         if ( CollectionUtils.isNotEmpty( listPrerequisite ) )
1420         {
1421             listPrerequisiteDTO = new ArrayList<>( listPrerequisite.size( ) );
1422 
1423             for ( Prerequisite prerequisite : listPrerequisite )
1424             {
1425                 IAutomaticActionPrerequisiteService prerequisiteService = _prerequisiteManagementService
1426                         .getPrerequisiteService( prerequisite.getPrerequisiteType( ) );
1427                 PrerequisiteDTOflow/business/prerequisite/PrerequisiteDTO.html#PrerequisiteDTO">PrerequisiteDTO dto = new PrerequisiteDTO( prerequisite, prerequisiteService.getTitleI18nKey( ), prerequisiteService.hasConfiguration( ) );
1428                 listPrerequisiteDTO.add( dto );
1429             }
1430         }
1431 
1432         if ( action.isAutomaticState( ) )
1433         {
1434             for ( ITaskType taskType : taskTypeList )
1435             {
1436                 if ( _taskFactory.newTask( taskType.getKey( ), getLocale( ) ).getTaskType( ).isTaskForAutomaticAction( ) )
1437                 {
1438                     refListTaskType.addItem( taskType.getKey( ), I18nService.getLocalizedString( taskType.getTitleI18nKey( ), getLocale( ) ) );
1439                 }
1440             }
1441         }
1442         else
1443         {
1444             refListTaskType = ReferenceList.convert( _workflowService.getMapTaskTypes( getLocale( ) ) );
1445         }
1446 
1447         setPageTitleProperty( PROPERTY_MODIFY_ACTION_PAGE_TITLE );
1448 
1449         List<ITask> taskList = _taskService.getListTaskByIdAction( nIdAction, getLocale( ) );
1450 
1451         Map<String, Object> model = new HashMap<>( );
1452         model.put( MARK_ACTION, action );
1453         model.put( MARK_STATE_LIST, WorkflowUtils.getRefList( listState, false, getLocale( ) ) );
1454         model.put( MARK_ALTERNATIVE_STATE_LIST, WorkflowUtils.getRefList( listState, true, getLocale( ) ) );
1455         model.put( MARK_TASK_TYPE_LIST, refListTaskType );
1456         model.put( MARK_TASK_LIST, taskList );
1457         model.put( MARK_NUMBER_TASK, taskList.size( ) );
1458         model.put( MARK_ICON_LIST, listIcon );
1459         model.put( MARK_PLUGIN, getPlugin( ) );
1460         model.put( MARK_LOCALE, getLocale( ) );
1461         model.put( MARK_LIST_PREREQUISITE, listPrerequisiteDTO );
1462         model.put( MARK_LIST_PREREQUISITE_TYPE, getPrerequisiteServiceRefList( getLocale( ) ) );
1463 
1464         boolean bDisplayTasksForm = _workflowService.isDisplayTasksForm( nIdAction, getLocale( ) );
1465         model.put( MARK_DISPLAY_TASKS_FORM, bDisplayTasksForm );
1466 
1467         // The action can be linked only it has no task that requires a form
1468         if ( !bDisplayTasksForm )
1469         {
1470             model.put( MARK_AVAILABLE_LINKED_ACTIONS, getAvailableActionsToLink( nIdAction, action.getWorkflow( ).getId( ) ) );
1471             model.put( MARK_SELECTED_LINKED_ACTIONS, getLinkedActions( nIdAction ) );
1472         }
1473         // Add CSRF token
1474         model.put( SecurityTokenService.MARK_TOKEN , SecurityTokenService.getInstance( ).getToken( request, TEMPLATE_MODIFY_ACTION ) );
1475 
1476         HtmlTemplate template = AppTemplateService.getTemplate( TEMPLATE_MODIFY_ACTION, getLocale( ), model );
1477 
1478         return getAdminPage( template.getHtml( ) );
1479     }
1480 
1481     /**
1482      * Get the list of prerequisites services
1483      * 
1484      * @param locale
1485      *            The locale
1486      * @return The list of prerequisite services
1487      */
1488     private ReferenceList getPrerequisiteServiceRefList( Locale locale )
1489     {
1490         ReferenceList refList = new ReferenceList( );
1491 
1492         for ( IAutomaticActionPrerequisiteService service : _prerequisiteManagementService.getPrerequisiteServiceList( ) )
1493         {
1494             refList.addItem( service.getPrerequisiteType( ), I18nService.getLocalizedString( service.getTitleI18nKey( ), locale ) );
1495         }
1496 
1497         return refList;
1498     }
1499 
1500     /**
1501      * Perform the workflow modification
1502      * 
1503      * @param request
1504      *            The HTTP request
1505      * @throws AccessDeniedException
1506      *             the {@link AccessDeniedException}
1507      * @return The URL to go after performing the action
1508      */
1509     public String doModifyAction( HttpServletRequest request ) throws AccessDeniedException
1510     {
1511         // Control the validity of the CSRF Token
1512         if ( !SecurityTokenService.getInstance( ).validate( request, TEMPLATE_MODIFY_ACTION ) )
1513         {
1514             throw new AccessDeniedException( I18nService.getLocalizedString( WorkflowUtils.MESSAGE_ERROR_INVALID_SECURITY_TOKEN, getLocale( ) ) );
1515         }
1516 
1517         String strIdAction = request.getParameter( PARAMETER_ID_ACTION );
1518         int nIdAction = WorkflowUtils.convertStringToInt( strIdAction );
1519         Action action = null;
1520 
1521         if ( nIdAction != WorkflowUtils.CONSTANT_ID_NULL )
1522         {
1523             action = _actionService.findByPrimaryKey( nIdAction );
1524         }
1525 
1526         if ( action == null )
1527         {
1528             throw new AccessDeniedException( LOG_ACTION_NOT_FOUND + nIdAction );
1529         }
1530 
1531         if ( request.getParameter( PARAMETER_CANCEL ) == null )
1532         {
1533             String strError = getActionData( request, action );
1534 
1535             if ( strError != null )
1536             {
1537                 return strError;
1538             }
1539 
1540             _actionService.update( action );
1541         }
1542 
1543         if ( request.getParameter( PARAMETER_APPLY ) != null )
1544         {
1545             return getJspModifyAction( request, nIdAction );
1546         }
1547 
1548         return getJspModifyWorkflow( request, action.getWorkflow( ).getId( ), PANE_ACTIONS );
1549     }
1550 
1551     /**
1552      * Gets the confirmation page of remove all Directory Record
1553      * 
1554      * @param request
1555      *            The HTTP request
1556      * @throws AccessDeniedException
1557      *             the {@link AccessDeniedException}
1558      * @return the confirmation page of delete all Directory Record
1559      */
1560     public String getConfirmRemoveAction( HttpServletRequest request ) throws AccessDeniedException
1561     {
1562         String strIdAction = request.getParameter( PARAMETER_ID_ACTION );
1563 
1564         UrlItem url = new UrlItem( JSP_DO_REMOVE_ACTION );
1565         url.addParameter( PARAMETER_ID_ACTION, strIdAction );
1566         url.addParameter( SecurityTokenService.PARAMETER_TOKEN, SecurityTokenService.getInstance( ).getToken( request, JSP_DO_REMOVE_ACTION ) );
1567 
1568         return AdminMessageService.getMessageUrl( request, MESSAGE_CONFIRM_REMOVE_ACTION, url.getUrl( ), AdminMessage.TYPE_CONFIRMATION );
1569     }
1570 
1571     /**
1572      * Remove all workflow record of the workflow
1573      * 
1574      * @param request
1575      *            The HTTP request
1576      * @throws AccessDeniedException
1577      *             the {@link AccessDeniedException}
1578      * @return The URL to go after performing the action
1579      */
1580     public String doRemoveAction( HttpServletRequest request ) throws AccessDeniedException
1581     {
1582         // Control the validity of the CSRF Token
1583         if ( !SecurityTokenService.getInstance( ).validate( request, JSP_DO_REMOVE_ACTION ) )
1584         {
1585             throw new AccessDeniedException( I18nService.getLocalizedString( WorkflowUtils.MESSAGE_ERROR_INVALID_SECURITY_TOKEN, getLocale( ) ) );
1586         }
1587 
1588         String strIdAction = request.getParameter( PARAMETER_ID_ACTION );
1589         int nIdAction = WorkflowUtils.convertStringToInt( strIdAction );
1590         Action action = _actionService.findByPrimaryKey( nIdAction );
1591 
1592         if ( action != null )
1593         {
1594             _prerequisiteManagementService.deletePrerequisiteByAction( nIdAction );
1595             _actionService.remove( nIdAction );
1596             _actionService.decrementOrderByOne( action.getOrder( ), action.getWorkflow( ).getId( ) );
1597 
1598             return getJspModifyWorkflow( request, action.getWorkflow( ).getId( ), PANE_ACTIONS );
1599         }
1600 
1601         return getJspManageWorkflow( request );
1602     }
1603 
1604     /**
1605      * Insert a new task in an Action
1606      * 
1607      * @param request
1608      *            The HTTP request
1609      * @throws AccessDeniedException
1610      *             the {@link AccessDeniedException}
1611      * @return The URL to go after performing the action
1612      */
1613     public String doInsertTask( HttpServletRequest request ) throws AccessDeniedException
1614     {
1615         // Control the validity of the CSRF Token
1616         if ( !SecurityTokenService.getInstance( ).validate( request, TEMPLATE_MODIFY_ACTION ) )
1617         {
1618             throw new AccessDeniedException( I18nService.getLocalizedString( WorkflowUtils.MESSAGE_ERROR_INVALID_SECURITY_TOKEN, getLocale( ) ) );
1619         }
1620 
1621         String strIdAction = request.getParameter( PARAMETER_ID_ACTION );
1622         int nIdAction = WorkflowUtils.convertStringToInt( strIdAction );
1623         String strTaskTypeKey = request.getParameter( PARAMETER_TASK_TYPE_KEY );
1624         String strUid = UUID.randomUUID().toString();
1625         Action action = _actionService.findByPrimaryKey( nIdAction );
1626         ITask task = _taskFactory.newTask( strTaskTypeKey, getLocale( ) );
1627 
1628         if ( ( action != null ) && ( task != null ) )
1629         {
1630             task.setAction( action );
1631             task.setUid(strUid);
1632 
1633             // get the maximum order number in this workflow and set max+1
1634             int nMaximumOrder = _taskService.findMaximumOrderByActionId( action.getId( ) );
1635             task.setOrder( nMaximumOrder + 1 );
1636 
1637             _taskService.create( task );
1638 
1639             // If the task requires a form, then remove any links to the action
1640             if ( task.getTaskType( ).isFormTaskRequired( ) )
1641             {
1642                 _actionService.removeLinkedActions( nIdAction );
1643             }
1644         }
1645 
1646         return getJspModifyAction( request, nIdAction );
1647     }
1648 
1649     /**
1650      * Gets the workflow creation page
1651      * 
1652      * @param request
1653      *            The HTTP request
1654      * @throws AccessDeniedException
1655      *             the {@link AccessDeniedException}
1656      * @return The workflow creation page
1657      */
1658     public String getModifyTask( HttpServletRequest request ) throws AccessDeniedException
1659     {
1660         String strIdTask = request.getParameter( PARAMETER_ID_TASK );
1661         int nIdTask = WorkflowUtils.convertStringToInt( strIdTask );
1662         ITask task = _taskService.findByPrimaryKey( nIdTask, getLocale( ) );
1663 
1664         if ( task == null )
1665         {
1666             throw new AccessDeniedException( "Task not found for ID " + nIdTask );
1667         }
1668 
1669         Map<String, Object> model = new HashMap<>( );
1670 
1671         model.put( MARK_TASK, task );
1672         model.put( MARK_TASK_CONFIG, _taskComponentManager.getDisplayConfigForm( request, getLocale( ), task ) );
1673         // Add CSRF Token
1674         model.put( SecurityTokenService.MARK_TOKEN , SecurityTokenService.getInstance( ).getToken( request, TEMPLATE_MODIFY_TASK ) );
1675 
1676         setPageTitleProperty( PROPERTY_MODIFY_TASK_PAGE_TITLE );
1677 
1678         HtmlTemplate template = AppTemplateService.getTemplate( TEMPLATE_MODIFY_TASK, getLocale( ), model );
1679 
1680         return getAdminPage( template.getHtml( ) );
1681     }
1682 
1683     /**
1684      * Modify task
1685      * 
1686      * @param request
1687      *            The HTTP request
1688      * @throws AccessDeniedException
1689      *             the {@link AccessDeniedException}
1690      * @return The URL to go after performing the action
1691      */
1692     public String doModifyTask( HttpServletRequest request ) throws AccessDeniedException
1693     {
1694         // Control the validity of the CSRF Token
1695         if ( !SecurityTokenService.getInstance( ).validate( request, TEMPLATE_MODIFY_TASK ) )
1696         {
1697             throw new AccessDeniedException( I18nService.getLocalizedString( WorkflowUtils.MESSAGE_ERROR_INVALID_SECURITY_TOKEN, getLocale( ) ) );
1698         }
1699 
1700         String strIdTask = request.getParameter( PARAMETER_ID_TASK );
1701         int nIdTask = WorkflowUtils.convertStringToInt( strIdTask );
1702         ITask task = _taskService.findByPrimaryKey( nIdTask, getLocale( ) );
1703 
1704         if ( task != null )
1705         {
1706             Action action = _actionService.findByPrimaryKey( task.getAction( ).getId( ) );
1707 
1708             if ( request.getParameter( PARAMETER_CANCEL ) == null )
1709             {
1710                 String strError = _taskComponentManager.doSaveConfig( request, getLocale( ), task );
1711 
1712                 if ( strError != null )
1713                 {
1714                     return strError;
1715                 }
1716 
1717                 if ( request.getParameter( PARAMETER_APPLY ) != null )
1718                 {
1719                     return getJspModifyTask( request, nIdTask );
1720                 }
1721             }
1722 
1723             if ( action.isAutomaticReflexiveAction( ) && !action.getListIdStateBefore( ).isEmpty( ) )
1724             {
1725                 return getJspModifyReflexiveAction( request, action.getListIdStateBefore( ).get( 0 ) );
1726             }
1727 
1728             return getJspModifyAction( request, task.getAction( ).getId( ) );
1729         }
1730 
1731         return getJspManageWorkflow( request );
1732     }
1733 
1734     /**
1735      * Gets the confirmation page of remove task
1736      * 
1737      * @param request
1738      *            The HTTP request
1739      * @throws AccessDeniedException
1740      *             the {@link AccessDeniedException}
1741      * @return the confirmation page of delete Task
1742      */
1743     public String getConfirmRemoveTask( HttpServletRequest request ) throws AccessDeniedException
1744     {
1745         String strId = request.getParameter( PARAMETER_ID_TASK );
1746 
1747         if ( StringUtils.isEmpty( strId ) || !StringUtils.isNumeric( strId ) )
1748         {
1749             return getJspManageWorkflow( request );
1750         }
1751 
1752         int nIdTask = Integer.parseInt( strId );
1753         ITask task = _taskService.findByPrimaryKey( nIdTask, getLocale( ) );
1754         Action action = _actionService.findByPrimaryKey( task.getAction( ).getId( ) );
1755         UrlItem url;
1756 
1757         if ( action.isAutomaticReflexiveAction( ) && !action.getListIdStateBefore( ).isEmpty( ) )
1758         {
1759             url = new UrlItem( JSP_DO_REMOVE_TASK_FROM_REFLEXIVE_ACTION );
1760             url.addParameter( PARAMETER_ID_TASK, strId );
1761             url.addParameter( PARAMETER_ID_STATE, action.getListIdStateBefore( ).get( 0 ) );
1762             url.addParameter( SecurityTokenService.PARAMETER_TOKEN, SecurityTokenService.getInstance( ).getToken( request, JSP_DO_REMOVE_TASK_FROM_REFLEXIVE_ACTION ) );
1763         }
1764         else
1765         {
1766             url = new UrlItem( JSP_DO_REMOVE_TASK );
1767             url.addParameter( PARAMETER_ID_TASK, strId );
1768             url.addParameter( SecurityTokenService.PARAMETER_TOKEN, SecurityTokenService.getInstance( ).getToken( request, JSP_DO_REMOVE_TASK ) );
1769         }
1770 
1771         return AdminMessageService.getMessageUrl( request, MESSAGE_CONFIRM_REMOVE_TASK, url.getUrl( ), AdminMessage.TYPE_CONFIRMATION );
1772     }
1773 
1774     /**
1775      * Remove all workflow record of the workflow
1776      * 
1777      * @param request
1778      *            The HTTP request
1779      * @param isReflexiveTask
1780      *            Set to true if a Reflexive Task ( automatic action ) is being removed, set to false otherwise
1781      * @throws AccessDeniedException
1782      *             the {@link AccessDeniedException}
1783      * @return The URL to go after performing the action
1784      */
1785     public String doRemoveTask( HttpServletRequest request, boolean isReflexiveTask ) throws AccessDeniedException
1786     {
1787         // Control the validity of the CSRF Token for both types of Task forms
1788         if ( !isReflexiveTask && !SecurityTokenService.getInstance( ).validate( request, JSP_DO_REMOVE_TASK ) )
1789         {
1790             throw new AccessDeniedException( I18nService.getLocalizedString( WorkflowUtils.MESSAGE_ERROR_INVALID_SECURITY_TOKEN, getLocale( ) ) );
1791         }
1792 
1793         String strIdTask = request.getParameter( PARAMETER_ID_TASK );
1794         int nIdTask = WorkflowUtils.convertStringToInt( strIdTask );
1795         ITask task = _taskService.findByPrimaryKey( nIdTask, getLocale( ) );
1796 
1797         if ( ( task != null ) && ( task.getTaskType( ) != null ) )
1798         {
1799             List<String> listErrors = new ArrayList<>( );
1800 
1801             if ( !TaskRemovalListenerService.getService( ).checkForRemoval( strIdTask, listErrors, getLocale( ) ) )
1802             {
1803                 String strCause = AdminMessageService.getFormattedList( listErrors, getLocale( ) );
1804                 Object [ ] arguments = {
1805                         strCause
1806                 };
1807 
1808                 return AdminMessageService.getMessageUrl( request, MESSAGE_CAN_NOT_REMOVE_TASK, arguments, AdminMessage.TYPE_STOP );
1809             }
1810 
1811             if ( task.getTaskType( ).isConfigRequired( ) )
1812             {
1813                 task.doRemoveConfig( );
1814             }
1815 
1816             _taskService.remove( nIdTask );
1817             _taskService.decrementOrderByOne( task.getOrder( ), task.getAction( ).getId( ) );
1818 
1819             Action action = _actionService.findByPrimaryKey( task.getAction( ).getId( ) );
1820 
1821             if ( action != null )
1822             {
1823                 UrlItem url = new UrlItem( AppPathService.getBaseUrl( request ) + JSP_MODIFY_ACTION );
1824                 url.addParameter( PARAMETER_ID_ACTION, task.getAction( ).getId( ) );
1825 
1826                 return url.getUrl( );
1827             }
1828         }
1829 
1830         return getJspManageWorkflow( request );
1831     }
1832 
1833     /**
1834      * copy the task whose key is specified in the Http request
1835      * 
1836      * @param request
1837      *            The HTTP request
1838      * @throws AccessDeniedException
1839      *             the {@link AccessDeniedException}
1840      * @return The URL to go after performing the action
1841      * @throws InvocationTargetException
1842      *             the {@link InvocationTargetException}
1843      * @throws IllegalAccessException
1844      *             the {@link IllegalAccessException}
1845      * @throws NoSuchMethodException
1846      *             the {@link NoSuchMethodException}
1847      */
1848     public String doCopyTask( HttpServletRequest request )
1849             throws AccessDeniedException, NoSuchMethodException, IllegalAccessException, InvocationTargetException
1850     {
1851         // Control the validity of the CSRF Token when duplicating regular tasks or Reflexive tasks
1852         if ( !SecurityTokenService.getInstance( ).validate( request, TEMPLATE_MODIFY_ACTION )
1853                 && !SecurityTokenService.getInstance( ).validate( request, TEMPLATE_MODIFY_REFLEXIVE_ACTION ) )
1854         {
1855             throw new AccessDeniedException( MESSAGE_ERROR_INVALID_SECURITY_TOKEN );
1856         }
1857 
1858         String strIdTask = request.getParameter( PARAMETER_ID_TASK );
1859         ITask taskToCopy;
1860         int nIdTaskToCopy = WorkflowUtils.convertStringToInt( strIdTask );
1861         taskToCopy = _taskService.findByPrimaryKey( nIdTaskToCopy, request.getLocale( ) );
1862 
1863         doCopyTaskWithModifiedParam( taskToCopy, null );
1864 
1865         Action action = _actionService.findByPrimaryKey( taskToCopy.getAction( ).getId( ) );
1866 
1867         if ( action.isAutomaticReflexiveAction( ) && !action.getListIdStateBefore( ).isEmpty( ) )
1868         {
1869             return getJspModifyReflexiveAction( request, action.getListIdStateBefore( ).get( 0 ) );
1870         }
1871 
1872         return getJspModifyAction( request, taskToCopy.getAction( ).getId( ) );
1873     }
1874 
1875     /**
1876      * Copy the task whose key is specified in the Http request and update param if exists
1877      * 
1878      * @param taskToCopy
1879      *            the task to copy
1880      * @param mapParamToChange
1881      *            the map of (Param, Value) to change
1882      * @throws NoSuchMethodException
1883      *             NoSuchMethodException the {@link NoSuchMethodException}
1884      * @throws IllegalAccessException
1885      *             IllegalAccessException the {@link IllegalAccessException}
1886      * @throws InvocationTargetException
1887      *             InvocationTargetException the {@link InvocationTargetException}
1888      */
1889     public void doCopyTaskWithModifiedParam( ITask taskToCopy, Map<String, String> mapParamToChange )
1890             throws NoSuchMethodException, IllegalAccessException, InvocationTargetException
1891     {
1892         // Save nIdTaskToCopy
1893         Integer nIdTaskToCopy = taskToCopy.getId( );
1894 
1895         // get the maximum order number in this workflow and set max+1
1896         int nMaximumOrder = _taskService.findMaximumOrderByActionId( taskToCopy.getAction( ).getId( ) );
1897         taskToCopy.setOrder( nMaximumOrder + 1 );
1898 
1899         // Create the new task (taskToCopy id will be update with the new
1900         // idTask)
1901         _taskService.create( taskToCopy );
1902 
1903         // get all taskConfigService
1904         List<ITaskConfigService> listTaskConfigService = SpringContextService.getBeansOfType( ITaskConfigService.class );
1905 
1906         // For each taskConfigService, update parameter if exists
1907         for ( ITaskConfigService taskConfigService : listTaskConfigService )
1908         {
1909             ITaskConfig taskConfig = taskConfigService.findByPrimaryKey( nIdTaskToCopy );
1910 
1911             if ( taskConfig != null )
1912             {
1913                 taskConfig.setIdTask( taskToCopy.getId( ) );
1914 
1915                 if ( mapParamToChange != null )
1916                 {
1917                     EntrySetMapIterator it = new EntrySetMapIterator( mapParamToChange );
1918 
1919                     while ( it.hasNext( ) )
1920                     {
1921                         String key = (String) it.next( );
1922                         String value = (String) it.getValue( );
1923                         MethodUtil.set( taskConfig, key, value );
1924                     }
1925                 }
1926 
1927                 taskConfigService.create( taskConfig );
1928             }
1929         }
1930     }
1931 
1932     /**
1933      * Returns advanced parameters form
1934      * 
1935      * @param request
1936      *            The Http request
1937      * @return Html form
1938      */
1939     public String getManageAdvancedParameters( HttpServletRequest request )
1940     {
1941         if ( !RBACService.isAuthorized( Action.RESOURCE_TYPE, RBAC.WILDCARD_RESOURCES_ID, ActionResourceIdService.PERMISSION_MANAGE_ADVANCED_PARAMETERS,
1942                 (User) getUser( ) ) )
1943         {
1944             return getManageWorkflow( request );
1945         }
1946 
1947         HtmlTemplate template = AppTemplateService.getTemplate( TEMPLATE_MANAGE_ADVANCED_PARAMETERS, getLocale( ) );
1948 
1949         return getAdminPage( template.getHtml( ) );
1950     }
1951 
1952     /**
1953      * return a reference list wich contains the different state of a workflow
1954      * 
1955      * @param locale
1956      *            the locale
1957      * @return reference list of workflow state
1958      */
1959     private ReferenceList getRefListActive( Locale locale )
1960     {
1961         ReferenceList refListState = new ReferenceList( );
1962         String strAll = I18nService.getLocalizedString( PROPERTY_ALL, locale );
1963         String strYes = I18nService.getLocalizedString( PROPERTY_YES, locale );
1964         String strNo = I18nService.getLocalizedString( PROPERTY_NO, locale );
1965 
1966         refListState.addItem( -1, strAll );
1967         refListState.addItem( 1, strYes );
1968         refListState.addItem( 0, strNo );
1969 
1970         return refListState;
1971     }
1972 
1973     /**
1974      * return url of the jsp modify workflow
1975      * 
1976      * @param request
1977      *            The HTTP request
1978      * @param nIdWorkflow
1979      *            the key of workflow to modify
1980      * @return return url of the jsp modify workflows
1981      */
1982     private String getJspModifyWorkflow( HttpServletRequest request, int nIdWorkflow )
1983     {
1984         return getJspModifyWorkflow( request, nIdWorkflow, null );
1985     }
1986 
1987     /**
1988      * return url of the jsp modify workflow
1989      * 
1990      * @param request
1991      *            The HTTP request
1992      * @param nIdWorkflow
1993      *            the key of workflow to modify
1994      * @param strPane
1995      *            The pane to display
1996      * @return return url of the jsp modify workflows
1997      */
1998     private String getJspModifyWorkflow( HttpServletRequest request, int nIdWorkflow, String strPane )
1999     {
2000         UrlItem url = new UrlItem( AppPathService.getBaseUrl( request ) + JSP_MODIFY_WORKFLOW );
2001         url.addParameter( PARAMETER_ID_WORKFLOW, nIdWorkflow );
2002 
2003         if ( strPane != null )
2004         {
2005             url.addParameter( PARAMETER_PANE, strPane );
2006         }
2007 
2008         return url.getUrl( );
2009     }
2010 
2011     /**
2012      * Return url of the jsp modify action
2013      * 
2014      * @param request
2015      *            The HTTP request
2016      * @param nIdTask
2017      *            the id task
2018      * @return return url of the jsp modify action
2019      */
2020     private String getJspModifyTask( HttpServletRequest request, int nIdTask )
2021     {
2022         return AppPathService.getBaseUrl( request ) + JSP_MODIFY_TASK + "?" + PARAMETER_ID_TASK + "=" + nIdTask;
2023     }
2024 
2025     /**
2026      * Return url of the jsp modify action
2027      * 
2028      * @param request
2029      *            The HTTP request
2030      * @param nIdAction
2031      *            The key of action to modify
2032      * @return return url of the jsp modify action
2033      */
2034     private String getJspModifyAction( HttpServletRequest request, int nIdAction )
2035     {
2036         UrlItem url = new UrlItem( AppPathService.getBaseUrl( request ) + JSP_MODIFY_ACTION );
2037         url.addParameter( PARAMETER_ID_ACTION, nIdAction );
2038 
2039         return url.getUrl( );
2040     }
2041 
2042     /**
2043      * Get the absolute URL of the JSP to modify the automatic reflexive action of a state
2044      * 
2045      * @param request
2046      *            The request
2047      * @param nIdState
2048      *            The id of the state
2049      * @return The absolute URL to the JSP
2050      */
2051     private String getJspModifyReflexiveAction( HttpServletRequest request, int nIdState )
2052     {
2053         UrlItem urlItem = new UrlItem( JSP_MODIFY_REFLEXIVE_ACTION );
2054         urlItem.addParameter( PARAMETER_ID_STATE, nIdState );
2055 
2056         return AppPathService.getBaseUrl( request ) + urlItem.getUrl( );
2057     }
2058 
2059     /**
2060      * Changes the order of a given state (the way it will be displayed in the list)
2061      * 
2062      * @param request
2063      *            The HTTP request
2064      * @return return url of the jsp change order state
2065      */
2066     public String doChangeOrderState( HttpServletRequest request )
2067     {
2068         // gets the state which needs to be changed (order)
2069         String strStateId = request.getParameter( PARAMETER_ID_STATE );
2070         String strWorkflowId = request.getParameter( PARAMETER_ID_WORKFLOW );
2071         String strOrderToSet = request.getParameter( PARAMETER_ORDER_ID );
2072         int nStateId = 0;
2073         int nWorkflowId = 0;
2074         int nOrderToSet = 0;
2075 
2076         if ( StringUtils.isNotBlank( strStateId ) )
2077         {
2078             nStateId = WorkflowUtils.convertStringToInt( strStateId );
2079         }
2080 
2081         if ( StringUtils.isNotBlank( strWorkflowId ) )
2082         {
2083             nWorkflowId = WorkflowUtils.convertStringToInt( strWorkflowId );
2084         }
2085 
2086         if ( StringUtils.isNotBlank( strOrderToSet ) )
2087         {
2088             nOrderToSet = WorkflowUtils.convertStringToInt( strOrderToSet );
2089         }
2090 
2091         State stateToChangeOrder = _stateService.findByPrimaryKey( nStateId );
2092 
2093         // order goes up
2094         if ( nOrderToSet < stateToChangeOrder.getOrder( ) )
2095         {
2096             List<State> listWithOrderAfterChosen = _stateService.findStatesAfterOrder( nOrderToSet, nWorkflowId );
2097 
2098             for ( State state : listWithOrderAfterChosen )
2099             {
2100                 if ( state.getOrder( ) != stateToChangeOrder.getOrder( ) )
2101                 {
2102                     if ( state.getOrder( ) < stateToChangeOrder.getOrder( ) )
2103                     {
2104                         state.setOrder( state.getOrder( ) + 1 );
2105                     }
2106 
2107                     _stateService.update( state );
2108                 }
2109             }
2110         }
2111 
2112         // order goes down
2113         else
2114         {
2115             // get all the states with the order lower that the chosen state
2116             List<State> listWithOrderBetweenChosen = _stateService.findStatesBetweenOrders( stateToChangeOrder.getOrder( ), nOrderToSet, nWorkflowId );
2117 
2118             // for all those states, we decrement the order
2119             for ( State state : listWithOrderBetweenChosen )
2120             {
2121                 if ( state.getOrder( ) != stateToChangeOrder.getOrder( ) )
2122                 {
2123                     state.setOrder( state.getOrder( ) - 1 );
2124                     _stateService.update( state );
2125                 }
2126             }
2127         }
2128 
2129         // for the chosen one, we change its order too
2130         stateToChangeOrder.setOrder( nOrderToSet );
2131         _stateService.update( stateToChangeOrder );
2132 
2133         UrlItem url = new UrlItem( AppPathService.getBaseUrl( request ) + JSP_MODIFY_WORKFLOW );
2134         url.addParameter( PARAMETER_ID_WORKFLOW, nWorkflowId );
2135 
2136         return url.getUrl( );
2137     }
2138 
2139     /**
2140      * Changes the order of a given action (the way it will be displayed in the list)
2141      * 
2142      * @param request
2143      *            The HTTP request
2144      * @return return url of the jsp change order action
2145      */
2146     public String doChangeOrderAction( HttpServletRequest request )
2147     {
2148         // gets the action which needs to be changed (order)
2149         String strActionId = request.getParameter( PARAMETER_ID_ACTION );
2150         String strWorkflowId = request.getParameter( PARAMETER_ID_WORKFLOW );
2151         String strOrderToSet = request.getParameter( PARAMETER_ORDER_ACTION_ID );
2152         int nActionId = 0;
2153         int nWorkflowId = 0;
2154         int nOrderToSet = 0;
2155 
2156         if ( StringUtils.isNotBlank( strActionId ) )
2157         {
2158             nActionId = WorkflowUtils.convertStringToInt( strActionId );
2159         }
2160 
2161         if ( StringUtils.isNotBlank( strWorkflowId ) )
2162         {
2163             nWorkflowId = WorkflowUtils.convertStringToInt( strWorkflowId );
2164         }
2165 
2166         if ( StringUtils.isNotBlank( strOrderToSet ) )
2167         {
2168             nOrderToSet = WorkflowUtils.convertStringToInt( strOrderToSet );
2169         }
2170 
2171         Action actionToChangeOrder = _actionService.findByPrimaryKey( nActionId );
2172 
2173         // order goes up
2174         if ( nOrderToSet < actionToChangeOrder.getOrder( ) )
2175         {
2176             List<Action> listWithOrderAfterChosen = _actionService.findStatesAfterOrder( nOrderToSet, nWorkflowId );
2177 
2178             for ( Action action : listWithOrderAfterChosen )
2179             {
2180                 if ( action.getOrder( ) != actionToChangeOrder.getOrder( ) )
2181                 {
2182                     if ( action.getOrder( ) < actionToChangeOrder.getOrder( ) )
2183                     {
2184                         action.setOrder( action.getOrder( ) + 1 );
2185                     }
2186 
2187                     _actionService.update( action );
2188                 }
2189             }
2190         }
2191 
2192         // order goes down
2193         else
2194         {
2195             // get all the actions with the order lower that the chosen action
2196             List<Action> listWithOrderBetweenChosen = _actionService.findStatesBetweenOrders( actionToChangeOrder.getOrder( ), nOrderToSet, nWorkflowId );
2197 
2198             // for all those action, we decrement the order
2199             for ( Action action : listWithOrderBetweenChosen )
2200             {
2201                 if ( action.getOrder( ) != actionToChangeOrder.getOrder( ) )
2202                 {
2203                     action.setOrder( action.getOrder( ) - 1 );
2204                     _actionService.update( action );
2205                 }
2206             }
2207         }
2208 
2209         // for the chosen one, we change its order too
2210         actionToChangeOrder.setOrder( nOrderToSet );
2211         _actionService.update( actionToChangeOrder );
2212 
2213         return getJspModifyWorkflow( request, nWorkflowId, PANE_ACTIONS );
2214     }
2215 
2216     /**
2217      * Changes the order of a given task (the way it will be displayed in the list)
2218      * 
2219      * @param request
2220      *            The HTTP request
2221      * @return return url of the jsp change order task
2222      */
2223     public String doChangeOrderTask( HttpServletRequest request )
2224     {
2225         // gets the task which needs to be changed (order)
2226         String strTaskId = request.getParameter( PARAMETER_ID_TASK );
2227         String strOrderToSet = request.getParameter( PARAMETER_ORDER_TASK_ID );
2228         int nTaskId = 0;
2229         int nOrderToSet = 0;
2230 
2231         if ( StringUtils.isNotBlank( strTaskId ) )
2232         {
2233             nTaskId = WorkflowUtils.convertStringToInt( strTaskId );
2234         }
2235 
2236         if ( StringUtils.isNotBlank( strOrderToSet ) )
2237         {
2238             nOrderToSet = WorkflowUtils.convertStringToInt( strOrderToSet );
2239         }
2240 
2241         ITask taskToChangeOrder = _taskService.findByPrimaryKey( nTaskId, this.getLocale( ) );
2242 
2243         // order goes up
2244         if ( nOrderToSet < taskToChangeOrder.getOrder( ) )
2245         {
2246             List<ITask> listWithOrderAfterChosen = _taskService.findTasksAfterOrder( nOrderToSet, taskToChangeOrder.getAction( ).getId( ), this.getLocale( ) );
2247 
2248             for ( ITask task : listWithOrderAfterChosen )
2249             {
2250                 if ( task.getOrder( ) != taskToChangeOrder.getOrder( ) )
2251                 {
2252                     if ( task.getOrder( ) < taskToChangeOrder.getOrder( ) )
2253                     {
2254                         task.setOrder( task.getOrder( ) + 1 );
2255                     }
2256 
2257                     _taskService.update( task );
2258                 }
2259             }
2260         }
2261 
2262         // order goes down
2263         else
2264         {
2265             // get all the actions with the order lower that the chosen action
2266             List<ITask> listWithOrderBetweenChosen = _taskService.findTasksBetweenOrders( taskToChangeOrder.getOrder( ), nOrderToSet,
2267                     taskToChangeOrder.getAction( ).getId( ), this.getLocale( ) );
2268 
2269             // for all those action, we decrement the order
2270             for ( ITask task : listWithOrderBetweenChosen )
2271             {
2272                 if ( task.getOrder( ) != taskToChangeOrder.getOrder( ) )
2273                 {
2274                     task.setOrder( task.getOrder( ) - 1 );
2275                     _taskService.update( task );
2276                 }
2277             }
2278         }
2279 
2280         // for the chosen one, we change its order too
2281         taskToChangeOrder.setOrder( nOrderToSet );
2282         _taskService.update( taskToChangeOrder );
2283 
2284         Action action = _actionService.findByPrimaryKey( taskToChangeOrder.getAction( ).getId( ) );
2285 
2286         if ( action.isAutomaticReflexiveAction( ) && !action.getListIdStateBefore( ).isEmpty( ) )
2287         {
2288             return getJspModifyReflexiveAction( request, action.getListIdStateBefore( ).get( 0 ) );
2289         }
2290 
2291         return getJspModifyAction( request, action.getId( ) );
2292     }
2293 
2294     /**
2295      * return url of the jsp manage workflow
2296      * 
2297      * @param request
2298      *            The HTTP request
2299      * @return url of the jsp manage workflow
2300      */
2301     private String getJspManageWorkflow( HttpServletRequest request )
2302     {
2303         return AppPathService.getBaseUrl( request ) + JSP_MANAGE_WORKFLOW;
2304     }
2305 
2306     /**
2307      * Get the available linked actions for a given action
2308      * 
2309      * @param nIdAction
2310      *            the ID action
2311      * @param nIdWorkflow
2312      *            the id workflow
2313      * @return a {@link ReferenceList}
2314      */
2315     private ReferenceList getAvailableActionsToLink( int nIdAction, int nIdWorkflow )
2316     {
2317         ReferenceList listLinkedActions = new ReferenceList( );
2318         Collection<Integer> listIdsLinkedAction = _actionService.getListIdsLinkedAction( nIdAction );
2319         ActionFilter filter = new ActionFilter( );
2320         filter.setAutomaticReflexiveAction( false );
2321         filter.setIdWorkflow( nIdWorkflow );
2322 
2323         for ( Action actionToLink : _actionService.getListActionByFilter( filter ) )
2324         {
2325             /**
2326              * The action can be linked only if the following conditions are met : - it should not already be in the list of linked action - it should not be
2327              * the action to link itself - it should not have any task that requires a form
2328              */
2329             if ( !listIdsLinkedAction.contains( actionToLink.getId( ) ) && ( actionToLink.getId( ) != nIdAction )
2330                     && !_workflowService.isDisplayTasksForm( actionToLink.getId( ), null ) )
2331             {
2332                 listLinkedActions.addItem( actionToLink.getId( ), actionToLink.getName( ) );
2333             }
2334         }
2335 
2336         return listLinkedActions;
2337     }
2338 
2339     /**
2340      * Get the linked actions of a given id action
2341      * 
2342      * @param nIdAction
2343      *            the id action
2344      * @return a {@link ReferenceList}
2345      */
2346     private ReferenceList getLinkedActions( int nIdAction )
2347     {
2348         ReferenceList listLinkedActions = new ReferenceList( );
2349 
2350         for ( int nIdLinkedAction : _actionService.getListIdsLinkedAction( nIdAction ) )
2351         {
2352             Action linkedAction = _actionService.findByPrimaryKey( nIdLinkedAction );
2353 
2354             if ( ( linkedAction != null ) && ( linkedAction.getId( ) != nIdAction ) )
2355             {
2356                 listLinkedActions.addItem( linkedAction.getId( ), linkedAction.getName( ) );
2357             }
2358         }
2359 
2360         return listLinkedActions;
2361     }
2362 
2363     /**
2364      * Get the selected linked actions
2365      * 
2366      * @param action
2367      *            the action
2368      * @param request
2369      *            the HTTP request
2370      * @return a collection of IDs action
2371      */
2372     private Collection<Integer> getSelectedLinkedActions( Action action, HttpServletRequest request )
2373     {
2374         Collection<Integer> listIdsLinkedAction = action.getListIdsLinkedAction( );
2375 
2376         if ( listIdsLinkedAction == null )
2377         {
2378             listIdsLinkedAction = new LinkedHashSet<>( );
2379         }
2380 
2381         // Remove unselected id linked action from the list
2382         String [ ] strUnselectedLinkedActions = request.getParameterValues( PARAMETER_UNSELECT_LINKED_ACTIONS );
2383 
2384         if ( ArrayUtils.isNotEmpty( strUnselectedLinkedActions ) && CollectionUtils.isNotEmpty( listIdsLinkedAction ) )
2385         {
2386             Integer [ ] listUnselectedLinkedActions = WorkflowUtils.convertStringToInt( strUnselectedLinkedActions );
2387             listIdsLinkedAction.removeAll( Arrays.asList( listUnselectedLinkedActions ) );
2388         }
2389 
2390         // Add selected linked actions
2391         String [ ] strSelectedLinkedActions = request.getParameterValues( PARAMETER_SELECT_LINKED_ACTIONS );
2392 
2393         if ( ( strSelectedLinkedActions != null ) && ( strSelectedLinkedActions.length > 0 ) )
2394         {
2395             Integer [ ] listSelectedLinkedActions = WorkflowUtils.convertStringToInt( strSelectedLinkedActions );
2396             listIdsLinkedAction.addAll( Arrays.asList( listSelectedLinkedActions ) );
2397         }
2398 
2399         return listIdsLinkedAction;
2400     }
2401 
2402     /**
2403      * duplicate a state
2404      * 
2405      * @param request
2406      *            The HTTP request
2407      * @return The URL to go after performing the action
2408      * @throws InvocationTargetException
2409      * @throws IllegalAccessException
2410      * @throws NoSuchMethodException
2411      * @throws AccessDeniedException 
2412      */
2413     public String doCopyState( HttpServletRequest request ) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, AccessDeniedException
2414     {
2415         // Control the validity of the CSRF Token
2416         if ( !SecurityTokenService.getInstance( ).validate( request, TEMPLATE_MODIFY_WORKFLOW ) )
2417         {
2418             throw new AccessDeniedException( I18nService.getLocalizedString( WorkflowUtils.MESSAGE_ERROR_INVALID_SECURITY_TOKEN, getLocale( ) ) );
2419         }
2420 
2421         String strIdState = request.getParameter( PARAMETER_ID_STATE );
2422         int nIdState = WorkflowUtils.convertStringToInt( strIdState );
2423         State stateInit = _stateService.findByPrimaryKey( nIdState );
2424 
2425         State stateToCopy = copyStateMethod( request, stateInit );
2426 
2427         // get all the actions of the workflow to copy
2428         ActionFilter automaticReflexiveActionFilter = new ActionFilter( );
2429         automaticReflexiveActionFilter.setIdWorkflow( stateToCopy.getWorkflow( ).getId( ) );
2430         automaticReflexiveActionFilter.setAutomaticReflexiveAction( true );
2431         automaticReflexiveActionFilter.setIdStateAfter( nIdState );
2432         automaticReflexiveActionFilter.setIdStateBefore( nIdState );
2433 
2434         List<Action> listAutomaticReflexiveActionsOfWorkflow = _actionService.getListActionByFilter( automaticReflexiveActionFilter );
2435 
2436         for ( Action action : listAutomaticReflexiveActionsOfWorkflow )
2437         {
2438             // get the maximum order number in this workflow and set max+1
2439             int nMaximumOrder = _actionService.findMaximumOrderByWorkflowId( action.getWorkflow( ).getId( ) );
2440             action.setOrder( nMaximumOrder + 1 );
2441 
2442             // get the linked tasks and duplicate them
2443             List<ITask> listLinkedTasks = _taskService.getListTaskByIdAction( action.getId( ), this.getLocale( ) );
2444 
2445             action.setStateAfter( stateToCopy );
2446             if ( !action.getListIdStateBefore( ).isEmpty( ) )
2447             {
2448             	action.getListIdStateBefore( ).set( 0, stateToCopy.getId( ) );
2449             }
2450             _actionService.create( action );
2451 
2452             for ( ITask task : listLinkedTasks )
2453             {
2454                 // for each we change the linked action
2455                 task.setAction( action );
2456 
2457                 // and then we create the new task duplicated
2458                 this.doCopyTaskWithModifiedParam( task, null );
2459             }
2460         }
2461 
2462         return getJspModifyWorkflow( request, stateToCopy.getWorkflow( ).getId( ) );
2463     }
2464 
2465     /**
2466      * Duplicate an action
2467      * 
2468      * @param request
2469      *            the request
2470      * @return the URL of the "modify workflow" page
2471      * @throws NoSuchMethodException
2472      *             If a method was not found
2473      * @throws IllegalAccessException
2474      *             If an illegal access is performed
2475      * @throws InvocationTargetException
2476      *             If an error occurs
2477      * @throws AccessDeniedException 
2478      */
2479     public String doCopyAction( HttpServletRequest request ) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, AccessDeniedException
2480     {
2481         // Control the validity of the CSRF Token
2482         if ( !SecurityTokenService.getInstance( ).validate( request, TEMPLATE_MODIFY_WORKFLOW ) )
2483         {
2484             throw new AccessDeniedException( I18nService.getLocalizedString( WorkflowUtils.MESSAGE_ERROR_INVALID_SECURITY_TOKEN, getLocale( ) ) );
2485         }
2486 
2487         String strIdAction = request.getParameter( PARAMETER_ID_ACTION );
2488         int nIdAction = WorkflowUtils.convertStringToInt( strIdAction );
2489 
2490         Action actionInit = _actionService.findByPrimaryKey( nIdAction );
2491 
2492         Action actionToCopy = copyActionMethod( request, actionInit );
2493 
2494         return getJspModifyWorkflow( request, actionToCopy.getWorkflow( ).getId( ), PANE_ACTIONS );
2495     }
2496 
2497     /**
2498      * Duplicate a workflow
2499      * 
2500      * @param request
2501      *            the request
2502      * @return the URL of the workflow management page
2503      * @throws InvocationTargetException
2504      *             If a method was not found
2505      * @throws IllegalAccessException
2506      *             If an illegal access is performed
2507      * @throws NoSuchMethodException
2508      *             If an error occurs
2509      * @throws AccessDeniedException 
2510      */
2511     public String doCopyWorkflow( HttpServletRequest request ) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, AccessDeniedException
2512     {
2513         // Control the validity of the CSRF Token
2514         if ( !SecurityTokenService.getInstance( ).validate( request, WorkflowUtils.CONSTANT_ACTION_MODIFY_WORKFLOW ) )
2515         {
2516             throw new AccessDeniedException( I18nService.getLocalizedString( WorkflowUtils.MESSAGE_ERROR_INVALID_SECURITY_TOKEN, getLocale( ) ) );
2517         }
2518 
2519         int nId = WorkflowUtils.convertStringToInt( request.getParameter( PARAMETER_ID_WORKFLOW ) );
2520 
2521         if ( nId == -1 )
2522         {
2523             return getJspManageWorkflow( request );
2524         }
2525 
2526         try
2527         {
2528             String json = WorkflowJsonService.getInstance( ).jsonExportWorkflow( nId );
2529             WorkflowJsonService.getInstance( ).jsonImportWorkflow( json, getLocale( ) );
2530         }
2531         catch( JsonProcessingException e )
2532         {
2533             AppLogService.debug( e.getMessage( ) );
2534         }
2535 
2536         return getJspManageWorkflow( request );
2537     }
2538 
2539     public String getConfirmCopyWorkflow( HttpServletRequest request )
2540     {
2541         UrlItem url = new UrlItem( JSP_DO_COPY_WORKFLOW );
2542         url.addParameter( PARAMETER_ID_WORKFLOW, request.getParameter( PARAMETER_ID_WORKFLOW ) );
2543         url.addParameter( SecurityTokenService.PARAMETER_TOKEN, SecurityTokenService.getInstance( ).getToken( request, WorkflowUtils.CONSTANT_ACTION_MODIFY_WORKFLOW ) );
2544 
2545         return AdminMessageService.getMessageUrl( request, MESSAGE_CONFIRM_COPY_WORKFLOW, url.getUrl( ), AdminMessage.TYPE_CONFIRMATION );
2546     }
2547 
2548     /**
2549      * Copy an action
2550      * 
2551      * @param request
2552      *            the request
2553      * @param actionToCopy
2554      *            the action to copy
2555      * @return action the action
2556      * @throws NoSuchMethodException
2557      *             If the method was not found
2558      * @throws IllegalAccessException
2559      *             The an illegal access occurs
2560      * @throws InvocationTargetException
2561      *             The an error occurs
2562      */
2563     private Action copyActionMethod( HttpServletRequest request, Action actionToCopy )
2564             throws NoSuchMethodException, IllegalAccessException, InvocationTargetException
2565     {
2566         // get the action
2567         String newNameForCopy = I18nService.getLocalizedString( PROPERTY_COPY_OF_ACTION, request.getLocale( ) ) + actionToCopy.getName( );
2568         actionToCopy.setName( newNameForCopy );
2569 
2570         // get the maximum order number in this workflow and set max+1
2571         int nMaximumOrder = _actionService.findMaximumOrderByWorkflowId( actionToCopy.getWorkflow( ).getId( ) );
2572         actionToCopy.setOrder( nMaximumOrder + 1 );
2573 
2574         // get the linked tasks and duplicate them
2575         List<ITask> listLinkedTasks = _taskService.getListTaskByIdAction( actionToCopy.getId( ), this.getLocale( ) );
2576         int idActionOld = actionToCopy.getId( );
2577 
2578         _actionService.create( actionToCopy );
2579         int idActionNew = actionToCopy.getId( );
2580 
2581         for ( ITask task : listLinkedTasks )
2582         {
2583             // for each we change the linked action
2584             task.setAction( actionToCopy );
2585 
2586             // and then we create the new task duplicated
2587             this.doCopyTaskWithModifiedParam( task, null );
2588         }
2589 
2590         _prerequisiteManagementService.copyPrerequisite( idActionOld, idActionNew );
2591         return actionToCopy;
2592     }
2593 
2594     /**
2595      * Method for copying a state
2596      * 
2597      * @param request
2598      *            the request
2599      * @param stateToCopy
2600      *            the state to copy
2601      * @return state the copy of stateToCopy
2602      */
2603     private State copyStateMethod( HttpServletRequest request, State stateToCopy )
2604     {
2605         String newNameForCopy = I18nService.getLocalizedString( PROPERTY_COPY_OF_STATE, request.getLocale( ) ) + stateToCopy.getName( );
2606         stateToCopy.setName( newNameForCopy );
2607         // get the maximum order number in this workflow and set max+1
2608         int nMaximumOrder = _stateService.findMaximumOrderByWorkflowId( stateToCopy.getWorkflow( ).getId( ) );
2609         stateToCopy.setOrder( nMaximumOrder + 1 );
2610         _stateService.create( stateToCopy );
2611         return stateToCopy;
2612     }
2613 
2614     /**
2615      * Updates the order of states
2616      * 
2617      * @param request
2618      *            The HTTP request
2619      * @throws AccessDeniedException
2620      *             the {@link AccessDeniedException}
2621      * @return The workflow creation page
2622      */
2623     public String doUpdateStateOrder( HttpServletRequest request ) throws AccessDeniedException
2624     {
2625         String strIdWorkflow = request.getParameter( PARAMETER_ID_WORKFLOW );
2626         int nIdWorkflow = WorkflowUtils.convertStringToInt( strIdWorkflow );
2627         Workflow workflow = null;
2628 
2629         if ( nIdWorkflow != WorkflowUtils.CONSTANT_ID_NULL )
2630         {
2631             workflow = _workflowService.findByPrimaryKey( nIdWorkflow );
2632         }
2633 
2634         if ( workflow == null )
2635         {
2636             throw new AccessDeniedException( LOG_WORKFLOW_NOT_FOUND + nIdWorkflow );
2637         }
2638 
2639         _stateService.initializeStateOrder( nIdWorkflow );
2640 
2641         return getJspModifyWorkflow( request, nIdWorkflow, PANE_STATES );
2642     }
2643 
2644     /**
2645      * Updates the order of actions
2646      * 
2647      * @param request
2648      *            The HTTP request
2649      * @throws AccessDeniedException
2650      *             the {@link AccessDeniedException}
2651      * @return The workflow creation page
2652      */
2653     public String doUpdateActionOrder( HttpServletRequest request ) throws AccessDeniedException
2654     {
2655         String strIdWorkflow = request.getParameter( PARAMETER_ID_WORKFLOW );
2656         int nIdWorkflow = WorkflowUtils.convertStringToInt( strIdWorkflow );
2657         Workflow workflow = null;
2658 
2659         if ( nIdWorkflow != WorkflowUtils.CONSTANT_ID_NULL )
2660         {
2661             workflow = _workflowService.findByPrimaryKey( nIdWorkflow );
2662         }
2663 
2664         if ( workflow == null )
2665         {
2666             throw new AccessDeniedException( LOG_WORKFLOW_NOT_FOUND + nIdWorkflow );
2667         }
2668 
2669         _actionService.initializeActionOrder( nIdWorkflow );
2670 
2671         return getJspModifyWorkflow( request, nIdWorkflow, PANE_ACTIONS );
2672     }
2673 
2674     /**
2675      * Updates the order of tasks
2676      * 
2677      * @param request
2678      *            The HTTP request
2679      * @throws AccessDeniedException
2680      *             the {@link AccessDeniedException}
2681      * @return The workflow creation page
2682      */
2683     public String doUpdateTaskOrder( HttpServletRequest request ) throws AccessDeniedException
2684     {
2685         String strIdAction = request.getParameter( PARAMETER_ID_ACTION );
2686         int nIdAction = WorkflowUtils.convertStringToInt( strIdAction );
2687         Action action = null;
2688 
2689         if ( nIdAction != WorkflowUtils.CONSTANT_ID_NULL )
2690         {
2691             action = _actionService.findByPrimaryKey( nIdAction );
2692         }
2693 
2694         if ( action == null )
2695         {
2696             throw new AccessDeniedException( LOG_ACTION_NOT_FOUND + nIdAction );
2697         }
2698 
2699         _taskService.initializeTaskOrder( nIdAction, this.getLocale( ) );
2700 
2701         if ( action.isAutomaticReflexiveAction( ) && !action.getListIdStateBefore( ).isEmpty( ) )
2702         {
2703             return getJspModifyReflexiveAction( request, action.getListIdStateBefore( ).get( 0 ) );
2704         }
2705 
2706         return getJspModifyAction( request, nIdAction );
2707     }
2708 
2709     /**
2710      * Get the modify reflexive action page
2711      * 
2712      * @param request
2713      *            The request
2714      * @return The modify reflexive action page, or the manage workflow page if no valid state id is specified
2715      */
2716     public String getModifyReflexiveAction( HttpServletRequest request )
2717     {
2718         String strIdState = request.getParameter( PARAMETER_ID_STATE );
2719 
2720         if ( StringUtils.isEmpty( strIdState ) || !StringUtils.isNumeric( strIdState ) )
2721         {
2722             return getManageWorkflow( request );
2723         }
2724 
2725         Locale locale = AdminUserService.getLocale( request );
2726         int nIdState = Integer.parseInt( strIdState );
2727         State state = _stateService.findByPrimaryKey( nIdState );
2728         Map<String, Object> model = new HashMap<>( );
2729 
2730         List<Action> listActions = getAutomaticReflexiveActionsFromState( nIdState );
2731         List<ITask> listTasks = new ArrayList<>( );
2732 
2733         if ( CollectionUtils.isNotEmpty( listActions ) )
2734         {
2735             for ( Action action : listActions )
2736             {
2737                 List<ITask> listTasksFound = _taskService.getListTaskByIdAction( action.getId( ), locale );
2738 
2739                 if ( CollectionUtils.isNotEmpty( listTasksFound ) )
2740                 {
2741                     listTasks.addAll( listTasksFound );
2742                 }
2743             }
2744 
2745             model.put( MARK_ACTION, listActions.get( 0 ) );
2746         }
2747 
2748         ReferenceList refListTaskType = new ReferenceList( );
2749         Collection<ITaskType> taskTypeList = _taskFactory.getAllTaskTypes( );
2750 
2751         for ( ITaskType taskType : taskTypeList )
2752         {
2753             if ( _taskFactory.newTask( taskType.getKey( ), getLocale( ) ).getTaskType( ).isTaskForAutomaticAction( ) )
2754             {
2755                 refListTaskType.addItem( taskType.getKey( ), I18nService.getLocalizedString( taskType.getTitleI18nKey( ), getLocale( ) ) );
2756             }
2757         }
2758 
2759         model.put( MARK_TASK_LIST, listTasks );
2760         model.put( MARK_TASK_TYPE_LIST, refListTaskType );
2761         model.put( MARK_NUMBER_TASK, listTasks.size( ) );
2762         model.put( MARK_STATE, state );
2763         model.put( SecurityTokenService.MARK_TOKEN , SecurityTokenService.getInstance( ).getToken( request, TEMPLATE_MODIFY_REFLEXIVE_ACTION ) );
2764 
2765         HtmlTemplate template = AppTemplateService.getTemplate( TEMPLATE_MODIFY_REFLEXIVE_ACTION, locale, model );
2766 
2767         return getAdminPage( template.getHtml( ) );
2768     }
2769 
2770     /**
2771      * Do create a task and add it to the reflexive action of a state
2772      * 
2773      * @param request
2774      *            The request
2775      * @return The next URL to redirect to
2776      * @throws AccessDeniedException 
2777      */
2778     public String doAddTaskToReflexiveAction( HttpServletRequest request ) throws AccessDeniedException
2779     {
2780         // Control the validity of the CSRF Token
2781         if ( !SecurityTokenService.getInstance( ).validate( request, TEMPLATE_MODIFY_REFLEXIVE_ACTION ) )
2782         {
2783             throw new AccessDeniedException( I18nService.getLocalizedString( WorkflowUtils.MESSAGE_ERROR_INVALID_SECURITY_TOKEN, getLocale( ) ) );
2784         }
2785 
2786         String strIdState = request.getParameter( PARAMETER_ID_STATE );
2787 
2788         if ( StringUtils.isEmpty( strIdState ) || !StringUtils.isNumeric( strIdState ) )
2789         {
2790             return getJspManageWorkflow( request );
2791         }
2792 
2793         int nIdState = Integer.parseInt( strIdState );
2794         Locale locale = AdminUserService.getLocale( request );
2795         List<Action> listActions = getAutomaticReflexiveActionsFromState( nIdState );
2796         Action action;
2797 
2798         if ( CollectionUtils.isNotEmpty( listActions ) )
2799         {
2800             action = listActions.get( 0 );
2801         }
2802         else
2803         {
2804             List<Icon> listIcons = _iconService.getListIcons( );
2805             action = new Action( );
2806 
2807             State state = _stateService.findByPrimaryKey( nIdState );
2808             //action.setStateBefore( state );
2809             List<Integer> lstStateBefore = Arrays.asList( state.getId( ) );
2810             action.setListIdStateBefore( lstStateBefore );
2811             action.setStateAfter( state );
2812             action.setAutomaticReflexiveAction( true );
2813             action.setAutomaticState( false );
2814             action.setDescription( StringUtils.EMPTY );
2815             action.setIcon( listIcons.get( 0 ) );
2816             action.setName( I18nService.getLocalizedString( MESSAGE_REFLEXIVE_ACTION_NAME, locale ) + " " + state.getName( ) );
2817             action.setMassAction( false );
2818             action.setOrder( 0 );
2819             action.setWorkflow( state.getWorkflow( ) );
2820             action.setUid( UUID.randomUUID( ).toString( ) );
2821             _actionService.create( action );
2822         }
2823 
2824         String strTaskTypeKey = request.getParameter( PARAMETER_TASK_TYPE_KEY );
2825         ITask task = _taskFactory.newTask( strTaskTypeKey, locale );
2826 
2827         if ( ( task != null ) && task.getTaskType( ).isTaskForAutomaticAction( ) )
2828         {
2829             task.setAction( action );
2830 
2831             // get the maximum order number in this workflow and set max+1
2832             int nMaximumOrder = _taskService.findMaximumOrderByActionId( action.getId( ) );
2833             task.setOrder( nMaximumOrder + 1 );
2834 
2835             _taskService.create( task );
2836         }
2837 
2838         return getJspModifyReflexiveAction( request, nIdState );
2839     }
2840 
2841     /**
2842      * Do delete a task and remove it from the reflexive action of a state. If the action has no more task, then it is removed
2843      * 
2844      * @param request
2845      *            The request
2846      * @return The next URL to redirect to
2847      * @throws AccessDeniedException
2848      *             If the user is not allowed to access this feature
2849      */
2850     public String doRemoveTaskFromReflexiveAction( HttpServletRequest request ) throws AccessDeniedException
2851     {
2852         // Control the validity of the CSRF Token
2853         if ( !SecurityTokenService.getInstance( ).validate( request, JSP_DO_REMOVE_TASK_FROM_REFLEXIVE_ACTION ) )
2854         {
2855             throw new AccessDeniedException( I18nService.getLocalizedString( WorkflowUtils.MESSAGE_ERROR_INVALID_SECURITY_TOKEN, getLocale( ) ) );
2856         }
2857 
2858         String strIdState = request.getParameter( PARAMETER_ID_STATE );
2859         String strIdTask = request.getParameter( PARAMETER_ID_TASK );
2860 
2861         if ( StringUtils.isEmpty( strIdState ) || !StringUtils.isNumeric( strIdState ) || StringUtils.isEmpty( strIdTask )
2862                 || !StringUtils.isNumeric( strIdTask ) )
2863         {
2864             return getManageWorkflow( request );
2865         }
2866 
2867         Locale locale = AdminUserService.getLocale( request );
2868         int nIdState = Integer.parseInt( strIdState );
2869 
2870         doRemoveTask( request, true );
2871 
2872         List<Action> listActions = getAutomaticReflexiveActionsFromState( nIdState );
2873 
2874         if ( CollectionUtils.isNotEmpty( listActions ) )
2875         {
2876             for ( Action action : listActions )
2877             {
2878                 List<ITask> listTasks = _taskService.getListTaskByIdAction( action.getId( ), locale );
2879 
2880                 if ( ( listTasks == null ) || listTasks.isEmpty( ) )
2881                 {
2882                     _actionService.remove( action.getId( ) );
2883                 }
2884             }
2885         }
2886 
2887         return getJspModifyReflexiveAction( request, nIdState );
2888     }
2889 
2890     /**
2891      * Get the list of automatic reflexive actions associated with a given state
2892      * 
2893      * @param nIdState
2894      *            The id of the state
2895      * @return The list of actions associated with the given state.
2896      */
2897     private List<Action> getAutomaticReflexiveActionsFromState( int nIdState )
2898     {
2899         ActionFilter filter = new ActionFilter( );
2900         filter.setAutomaticReflexiveAction( true );
2901         filter.setIdStateBefore( nIdState );
2902 
2903         return _actionService.getListActionByFilter( filter );
2904     }
2905 
2906     /**
2907      * Export Workflow as Json
2908      * 
2909      * @param request
2910      */
2911     public void doExportWorkflow( HttpServletRequest request, HttpServletResponse response )
2912     {
2913         int nId = WorkflowUtils.convertStringToInt( request.getParameter( PARAMETER_ID_WORKFLOW ) );
2914 
2915         if ( nId == -1 )
2916         {
2917             return;
2918         }
2919 
2920         String content;
2921         try ( OutputStream os = response.getOutputStream( ) )
2922         {
2923             content = WorkflowJsonService.getInstance( ).jsonExportWorkflow( nId );
2924             Workflow workflow = _workflowService.findByPrimaryKey( nId );
2925 
2926             MVCUtils.addDownloadHeaderToResponse( response, FileUtil.normalizeFileName( workflow.getName( ) ) + ".json", "application/json" );
2927             os.write( content.getBytes( StandardCharsets.UTF_8 ) );
2928         }
2929         catch( IOException e )
2930         {
2931             AppLogService.error( e.getMessage( ), e );
2932         }
2933     }
2934 
2935     public String getConfirmImportWorkflow( HttpServletRequest request )
2936     {
2937         MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
2938         _importWorkflowFile = multipartRequest.getFile( PARAMETER_JSON_FILE );
2939         if(!_importWorkflowFile.getName().isEmpty()) {
2940             UrlItem url = new UrlItem( JSP_DO_IMPORT_WORKFLOW );
2941             return AdminMessageService.getMessageUrl( (MultipartHttpServletRequest) request, MESSAGE_CONFIRM_COPY_WORKFLOW, url.getUrl( ),
2942                     AdminMessage.TYPE_CONFIRMATION );
2943         }
2944         UrlItem url = new UrlItem( JSP_MANAGE_WORKFLOW );
2945         return AdminMessageService.getMessageUrl( (MultipartHttpServletRequest) request, ERROR_NO_FILE_SELECTED, url.getUrl( ),
2946                 AdminMessage.TYPE_ERROR );
2947     }
2948 
2949     public String doImportWorkflow( HttpServletRequest request )
2950     {
2951         try
2952         {
2953             if ( _importWorkflowFile != null )
2954             {
2955                 WorkflowJsonService.getInstance( ).jsonImportWorkflow( new String( _importWorkflowFile.get( ), StandardCharsets.UTF_8 ), getLocale( ) );
2956             }
2957         }
2958         catch( JsonProcessingException e )
2959         {
2960             AppLogService.error( e.getMessage( ) );
2961         }
2962         finally
2963         {
2964             _importWorkflowFile = null;
2965         }
2966         return getJspManageWorkflow( request );
2967     }
2968 }