WorkflowJsonService.java
/*
* Copyright (c) 2002-2022, City of Paris
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright notice
* and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice
* and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* 3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* License 1.0
*/
package fr.paris.lutece.plugins.workflow.service.json;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.transaction.annotation.Transactional;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import fr.paris.lutece.plugins.workflow.service.prerequisite.PrerequisiteManagementService;
import fr.paris.lutece.plugins.workflow.service.task.TaskFactory;
import fr.paris.lutece.plugins.workflow.utils.WorkflowUtils;
import fr.paris.lutece.plugins.workflowcore.business.action.Action;
import fr.paris.lutece.plugins.workflowcore.business.action.ActionFilter;
import fr.paris.lutece.plugins.workflowcore.business.prerequisite.Prerequisite;
import fr.paris.lutece.plugins.workflowcore.business.state.State;
import fr.paris.lutece.plugins.workflowcore.business.workflow.Workflow;
import fr.paris.lutece.plugins.workflowcore.service.action.ActionService;
import fr.paris.lutece.plugins.workflowcore.service.action.IActionService;
import fr.paris.lutece.plugins.workflowcore.service.prerequisite.IAutomaticActionPrerequisiteService;
import fr.paris.lutece.plugins.workflowcore.service.prerequisite.IPrerequisiteManagementService;
import fr.paris.lutece.plugins.workflowcore.service.state.IStateService;
import fr.paris.lutece.plugins.workflowcore.service.state.StateService;
import fr.paris.lutece.plugins.workflowcore.service.task.ITask;
import fr.paris.lutece.plugins.workflowcore.service.task.ITaskFactory;
import fr.paris.lutece.plugins.workflowcore.service.task.ITaskService;
import fr.paris.lutece.plugins.workflowcore.service.task.TaskService;
import fr.paris.lutece.plugins.workflowcore.service.workflow.IWorkflowService;
import fr.paris.lutece.plugins.workflowcore.service.workflow.WorkflowService;
import fr.paris.lutece.portal.service.i18n.I18nService;
import fr.paris.lutece.portal.service.spring.SpringContextService;
public class WorkflowJsonService
{
private static final String PROPERTY_COPY_WF_TITLE = "workflow.manage_workflow.copy_of_workflow";
public static final WorkflowJsonService INSTANCE = new WorkflowJsonService( );
private ObjectMapper _objectMapper;
private IWorkflowService _workflowService = SpringContextService.getBean( WorkflowService.BEAN_SERVICE );
private IStateService _stateService = SpringContextService.getBean( StateService.BEAN_SERVICE );
private IActionService _actionService = SpringContextService.getBean( ActionService.BEAN_SERVICE );
private ITaskService _taskService = SpringContextService.getBean( TaskService.BEAN_SERVICE );
private ITaskFactory _taskFactory = SpringContextService.getBean( TaskFactory.BEAN_SERVICE );
private IPrerequisiteManagementService _prerequisiteManagementService = SpringContextService.getBean( PrerequisiteManagementService.BEAN_NAME );
private WorkflowJsonService( )
{
SimpleModule timestampModule = new SimpleModule( "TimestampModule" );
timestampModule.addSerializer( Timestamp.class, new TimestampSerializer( ) );
timestampModule.addDeserializer( Timestamp.class, new TimestampDeserializer( ) );
SimpleModule taskModule = new SimpleModule( "TaskModule" );
taskModule.addSerializer( ITask.class, new TaskSerialiser( ) );
taskModule.addDeserializer( ITask.class, new TaskDeserializer( ) );
_objectMapper = new ObjectMapper( ).configure( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false ).registerModule( timestampModule )
.registerModule( taskModule );
}
public static WorkflowJsonService getInstance( )
{
return INSTANCE;
}
/**
* Export the workflow as a Json Object.
*
* @return
* @throws JsonProcessingException
*/
public String jsonExportWorkflow( int idWorkflow ) throws JsonProcessingException
{
WorkflowJsonData jsonData = new WorkflowJsonData( );
Workflow workflow = _workflowService.findByPrimaryKey( idWorkflow );
if( workflow.getUid( ) == null ){
workflow.setUid( UUID.randomUUID( ).toString( ) );
}
jsonData.setWorkflow( workflow );
List<State> stateList = (List<State>) _workflowService.getAllStateByWorkflow( workflow.getId( ) );
stateList.forEach(state -> {
if( state.getUid( ) == null ){
state.setUid( UUID.randomUUID( ).toString( ) );
}
});
jsonData.setStateList( stateList );
List<Action> actionList = new ArrayList<>( );
ActionFilter filter = new ActionFilter( );
filter.setIdWorkflow( workflow.getId( ) );
actionList.addAll( _actionService.getListActionByFilter( filter ) );
actionList.forEach(action -> {
if( action.getUid( ) == null ){
action.setUid( UUID.randomUUID( ).toString( ) );
}
});
for( Action action : actionList )
{
State actionStateAfter = _stateService.findByPrimaryKey( action.getStateAfter( ).getId( ) );
action.setStrUidStateAfter( actionStateAfter.getUid( ) );
if(action.getAlternativeStateAfter().getId() != -1) {
State actionAlternativeStateAfter = _stateService.findByPrimaryKey( action.getAlternativeStateAfter( ).getId( ) );
action.setStrUidAlternativeStateAfter( actionAlternativeStateAfter.getUid( ) );
}
List<String> listUidStateBefore = new ArrayList<>( );
action.getListIdStateBefore( ).forEach( stateId ->
{
listUidStateBefore.add( _stateService.findByPrimaryKey( stateId ).getUid( ) );
});
action.setListUidStateBefore( listUidStateBefore );
}
jsonData.setActionList( actionList );
List<ITask> taskList = new ArrayList<>( );
List<Prerequisite> prerequisiteList = new ArrayList<>( );
for ( Action action : actionList )
{
taskList.addAll( _taskService.getListTaskByIdAction( action.getId( ), Locale.getDefault( ) ) );
prerequisiteList.addAll( _prerequisiteManagementService.getListPrerequisite( action.getId( ) ) );
}
taskList.forEach(task -> {
if( task.getUid( ) == null ){
task.setUid( UUID.randomUUID( ).toString( ) );
}
});
for ( ITask task : taskList )
{
task.setActionUid( _actionService.findByPrimaryKey( task.getAction( ).getId( ) ).getUid( ) );
}
prerequisiteList.forEach(prerequisite -> {
if( prerequisite.getUidPrerequisite( ) == null ){
prerequisite.setUidPrerequisite( UUID.randomUUID( ).toString( ) );
}
});
for( Prerequisite prerequisite : prerequisiteList )
{
prerequisite.setUidAction( _actionService.findByPrimaryKey( prerequisite.getIdAction() ).getUid( ) );
}
jsonData.setTaskList( taskList );
jsonData.setPrerequisiteList( prerequisiteList );
return _objectMapper.writeValueAsString( jsonData );
}
@Transactional
public void jsonImportWorkflow( String json, Locale locale ) throws JsonProcessingException
{
WorkflowJsonData jsonData = _objectMapper.readValue( json, WorkflowJsonData.class );
int newIdWf = importWorkflow( jsonData.getWorkflow( ), locale );
List<State> stateList = jsonData.getStateList( );
List<Action> actionList = jsonData.getActionList( );
List<ITask> taskList = jsonData.getTaskList( );
List<Prerequisite> prerequisiteList = jsonData.getPrerequisiteList( );
importStates( newIdWf, stateList, actionList );
importActions( actionList, taskList, prerequisiteList );
importTasks( taskList );
importPrerequisites( prerequisiteList );
}
public int importWorkflow( Workflow workflow, Locale locale )
{
String strNameCopyWf = I18nService.getLocalizedString( PROPERTY_COPY_WF_TITLE, locale );
if ( strNameCopyWf != null )
{
workflow.setName( strNameCopyWf + workflow.getName( ) );
}
workflow.setEnabled( false );
workflow.setCreationDate( WorkflowUtils.getCurrentTimestamp( ) );
_workflowService.create( workflow );
return workflow.getId( );
}
private void importStates( int newIdWf, List<State> stateList, List<Action> actionList )
{
Map<String, Integer> mapIdStates = new HashMap<>( );
Workflow workflow = _workflowService.findByPrimaryKey( newIdWf );
for ( State state : stateList )
{
String uid = state.getUid( );
state.setWorkflow( workflow );
_stateService.create( state );
int newId = state.getId( );
mapIdStates.put( uid, newId );
}
updateActionWithStateAndWf( newIdWf, actionList, mapIdStates );
}
private void updateActionWithStateAndWf( int newIdWf, List<Action> actionList, Map<String, Integer> mapIdStates )
{
Workflow workflow = _workflowService.findByPrimaryKey( newIdWf );
for ( Action action : actionList )
{
action.setWorkflow( workflow );
action.setStateAfter( _stateService.findByPrimaryKey( mapIdStates.get( action.getStrUidStateAfter( ) ) ) );
if(action.getStrUidAlternativeStateAfter( ) != null) {
action.setAlternativeStateAfter( _stateService.findByPrimaryKey( mapIdStates.get( action.getStrUidAlternativeStateAfter( ) ) ) );
}
updateStateBefore(action, mapIdStates);
}
}
private void updateStateBefore(Action action, Map<String, Integer> mapIdStates) {
if(action.getListUidStateBefore( ) != null) {
List<Integer> StateBefore = new ArrayList<Integer>();
for (String strStateBefore : action.getListUidStateBefore( ) )
{
StateBefore.add(mapIdStates.get( strStateBefore ));
}
action.setListIdStateBefore( StateBefore );
}
}
private void importActions( List<Action> actionList, List<ITask> taskList, List<Prerequisite> prerequisiteList )
{
Map<String, Integer> mapIdActions = new HashMap<>( );
for ( Action action : actionList )
{
String uid = action.getUid( );
if(uid == null || uid.isEmpty())
{
action.setListIdStateBefore( new ArrayList<Integer>( ) );
action.setListIdsLinkedAction( new ArrayList<Integer>( ) );
}
_actionService.create( action );
int newId = action.getId( );
mapIdActions.put( uid, newId );
}
// Update Linked Actions
for ( Action action : actionList )
{
Collection<String> listUid = action.getListUidsLinkedAction( );
if ( CollectionUtils.isNotEmpty( listUid ) )
{
Collection<Integer> listNewId = listUid.stream( ).map( mapIdActions::get ).collect( Collectors.toList( ) );
action.setListIdsLinkedAction( listNewId );
_actionService.update( action );
}
}
updateTaskWithActions( taskList, mapIdActions );
updatePrerequisiteWithActions( prerequisiteList, mapIdActions );
}
private void updateTaskWithActions( List<ITask> taskList, Map<String, Integer> mapIdActions )
{
for ( ITask task : taskList )
{
Action action = _actionService.findByPrimaryKey( mapIdActions.get( task.getAction( ).getUid( ) ) );
if(action != null) {
task.setAction( action );
}
}
}
private void updatePrerequisiteWithActions( List<Prerequisite> prerequisiteList, Map<String, Integer> mapIdActions )
{
for ( Prerequisite prerequisite : prerequisiteList )
{
Action action = _actionService.findByPrimaryKey( mapIdActions.get( prerequisite.getUidAction( ) ) );
if ( action != null )
{
prerequisite.setIdAction( mapIdActions.get( action.getUid( ) ) );
}
}
}
private void importTasks( List<ITask> taskList )
{
for ( ITask task : taskList )
{
if( _taskFactory.getAllTaskTypes( ).stream( ).anyMatch( type -> type.getTitle( ) == task.getTaskType( ).getTitle( ) ) ) {
task.setTaskType( _taskFactory.getAllTaskTypes( ).stream( )
.filter( type -> type.getTitle( ) == task.getTaskType( ).getTitle( ) )
.findFirst( ).orElse(null) );
_taskService.create( task );
}
}
}
private void importPrerequisites( List<Prerequisite> prerequisiteList )
{
List<String> PrerequisiteTypeList = new ArrayList<String>();
for ( IAutomaticActionPrerequisiteService service : _prerequisiteManagementService.getPrerequisiteServiceList( ) )
{
PrerequisiteTypeList.add( service.getPrerequisiteType( ) );
}
for ( Prerequisite prerequisite : prerequisiteList )
{
if( PrerequisiteTypeList.contains( prerequisite.getPrerequisiteType( ) ) )
{
_prerequisiteManagementService.createPrerequisite( prerequisite );
}
}
}
}