package ee.telekom.workflow.example.listener;
import java.lang.invoke.MethodHandles;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import ee.telekom.workflow.facade.WorkflowEngineFacade;
import ee.telekom.workflow.facade.model.WorkItemState;
import ee.telekom.workflow.listener.HumanTaskEvent;
import ee.telekom.workflow.listener.HumanTaskEventListener;
/**
* If enabled, this listener auto-completes all example workflow human tasks.
* Useful for performance testing, when we don't want to wait for human input.
*
* @author Erko Hansar
*/
@Component
public class HumanTaskAutoCompleter implements HumanTaskEventListener{
private static final Logger log = LoggerFactory.getLogger( MethodHandles.lookup().lookupClass() );
// toggle this flag to enable the feature for performance testing
private static final boolean AUTO_COMPLETE_ENABLED = false;
@Autowired
private WorkflowEngineFacade facade;
private final Queue<Pair<Long, Integer>> queue = new ConcurrentLinkedQueue<>();
private final AtomicBoolean isStopped = new AtomicBoolean( true );
private Thread thread = null;
@Override
public void onCreated( HumanTaskEvent event ){
if( AUTO_COMPLETE_ENABLED ){
log.info( "Adding human task to auto complete queue: " + event.getWoinRefNum() + ", " + event.getTokenId() );
queue.add( Pair.of( event.getWoinRefNum(), event.getTokenId() ) );
}
}
@Override
public void onCompleted( HumanTaskEvent event, Object humanTaskResult ){
// do nothing
}
@Override
public void onCancelled( HumanTaskEvent event ){
// do nothing
}
///// PRIVATE METHODS /////
@PostConstruct
private void initCompleter() throws Exception{
if( AUTO_COMPLETE_ENABLED ){
log.debug( "Starting up HumanTaskAutoCompleter" );
isStopped.set( false );
thread = new Thread( new HTAutoCompleter() );
thread.start();
}
}
@PreDestroy
private void destroyCompleter() throws Exception{
if( AUTO_COMPLETE_ENABLED ){
log.debug( "Shutting down HumanTaskAutoCompleter" );
isStopped.set( true );
thread.join();
}
}
private class HTAutoCompleter implements Runnable{
@Override
public void run(){
log.info( "Started HTAutoCompleter on thread {}", Thread.currentThread().getName() );
mainLoop : while( true ){
// loop until queue has an item
Pair<Long, Integer> item = null;
while( item == null ){
if( isStopped.get() ){
break mainLoop;
}
item = queue.poll();
sleepIfNull( item );
}
// loop until matching WorkItem is found
WorkItemState woit = null;
while( woit == null ){
if( isStopped.get() ){
break mainLoop;
}
woit = facade.findActiveWorkItemByTokenId( item.getLeft(), item.getRight() );
sleepIfNull( woit );
}
log.info( "Auto-completing human task: " + woit.getRefNum() );
facade.submitHumanTask( woit.getRefNum(), false );
}
log.info( "Stopped HTAutoCompleter on thread {}", Thread.currentThread().getName() );
}
private void sleepIfNull( Object object ){
if( object == null ){
try{
Thread.sleep( 1000 );
}
catch( InterruptedException e ){
log.warn( "HTAutoCompleter error", e );
}
}
}
}
}