package ee.telekom.workflow.executor.marshall;
import java.lang.invoke.MethodHandles;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import ee.telekom.workflow.core.archive.ArchiveDao;
import ee.telekom.workflow.core.common.UnexpectedStatusException;
import ee.telekom.workflow.core.workflowinstance.WorkflowInstance;
import ee.telekom.workflow.core.workflowinstance.WorkflowInstanceDao;
import ee.telekom.workflow.core.workflowinstance.WorkflowInstanceStatus;
import ee.telekom.workflow.core.workitem.WorkItem;
import ee.telekom.workflow.core.workitem.WorkItemDao;
import ee.telekom.workflow.executor.GraphEngineFactory;
import ee.telekom.workflow.graph.Graph;
import ee.telekom.workflow.graph.GraphInstance;
import ee.telekom.workflow.graph.WorkItemStatus;
@Repository
@Transactional
public class GraphInstanceRepositoryImpl implements GraphInstanceRepository{
private static final Logger log = LoggerFactory.getLogger( MethodHandles.lookup().lookupClass() );
//NB! This class does not use service layer methods as it comprises a repository (located between
// the service and DAO layer).
@Autowired
private WorkflowInstanceDao woinDao;
@Autowired
private WorkItemDao woitDao;
@Autowired
private ArchiveDao archiveDao;
@Autowired
private GraphEngineFactory engineFactory;
@Override
public GraphInstance load( long woinRefNum ){
WorkflowInstance workflowInstance = woinDao.findByRefNum( woinRefNum );
List<WorkItem> workItems = woitDao.findActiveByWoinRefNum( woinRefNum );
Graph graph = engineFactory.getGraph( workflowInstance.getWorkflowName(), workflowInstance.getWorkflowVersion() );
return Marshaller.unmarshall( workflowInstance, workItems, graph );
}
@Override
public void save( GraphInstance graphInstance, WorkflowInstanceStatus completeStatus ){
WorkflowInstance workflowInstance = new WorkflowInstance();
List<WorkItem> workItems = new LinkedList<>();
Marshaller.marshall( graphInstance, workflowInstance, workItems, completeStatus );
List<Long> markCancelled = new LinkedList<>();
Long markCompleted = null;
List<WorkItem> createNew = new LinkedList<>();
for( WorkItem woit : workItems ){
if( woit.getRefNum() != null ){
if( WorkItemStatus.CANCELLED.equals( woit.getStatus() ) ){
markCancelled.add( woit.getRefNum() );
}
else if( WorkItemStatus.COMPLETED.equals( woit.getStatus() ) ){
markCompleted = woit.getRefNum();
}
}
else{
createNew.add( woit );
}
}
if( !markCancelled.isEmpty() ){
Collection<WorkItemStatus> expectedStatuses = Arrays.asList( WorkItemStatus.NEW, WorkItemStatus.EXECUTED );
boolean sucess = woitDao.updateStatus( markCancelled, WorkItemStatus.CANCELLED, expectedStatuses );
if( !sucess ){
throw new UnexpectedStatusException( expectedStatuses );
}
if( log.isInfoEnabled() ){
log.info( "Cancelled work items {} ", StringUtils.join( markCancelled, "," ) );
}
}
if( markCompleted != null ){
Collection<WorkItemStatus> expectedStatuses = Arrays.asList( WorkItemStatus.COMPLETING );
boolean sucess = woitDao.updateStatus( markCompleted, WorkItemStatus.COMPLETED, expectedStatuses );
if( !sucess ){
throw new UnexpectedStatusException( expectedStatuses );
}
log.info( "Completed work item {} ", markCompleted );
}
if( !createNew.isEmpty() ){
woitDao.create( createNew );
if( log.isInfoEnabled() ){
log.info( "Created new work items {} ", StringUtils.join( getRefNums( createNew ), "," ) );
}
}
List<WorkflowInstanceStatus> expectedStatuses = Arrays.asList(
WorkflowInstanceStatus.STARTING,
WorkflowInstanceStatus.EXECUTING,
WorkflowInstanceStatus.ABORTING );
boolean success = woinDao.updateAndUnlock(
workflowInstance.getRefNum(),
workflowInstance.getWorkflowVersion(),
workflowInstance.getAttributes(),
workflowInstance.getHistory(),
workflowInstance.getState(),
workflowInstance.getStatus(),
expectedStatuses
);
if( !success ){
throw new UnexpectedStatusException( expectedStatuses );
}
log.info( "Updated workflow instance {} with status {} ", workflowInstance.getRefNum(), workflowInstance.getStatus() );
if( WorkflowInstanceStatus.EXECUTED.equals( workflowInstance.getStatus() )
|| WorkflowInstanceStatus.ABORTED.equals( workflowInstance.getStatus() ) ){
archiveDao.archive( workflowInstance.getRefNum() );
log.info( "Archived workflow instance {}", workflowInstance.getRefNum() );
}
}
private List<Long> getRefNums( List<WorkItem> workItems ){
List<Long> result = new ArrayList<Long>( workItems.size() );
for( WorkItem wi : workItems ){
result.add( wi.getRefNum() );
}
return result;
}
}