Package pl.net.bluesoft.rnd.pt.ext.jbpm

Source Code of pl.net.bluesoft.rnd.pt.ext.jbpm.ProcessToolJbpmSession

package pl.net.bluesoft.rnd.pt.ext.jbpm;

import static pl.net.bluesoft.util.lang.FormatUtil.nvl;
import static pl.net.bluesoft.util.lang.Lang.keyFilter;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.aperteworkflow.bpm.graph.GraphElement;
import org.aperteworkflow.bpm.graph.StateNode;
import org.aperteworkflow.bpm.graph.TransitionArc;
import org.aperteworkflow.ui.view.ViewEvent;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.jbpm.api.Execution;
import org.jbpm.api.ExecutionService;
import org.jbpm.api.HistoryService;
import org.jbpm.api.IdentityService;
import org.jbpm.api.NewDeployment;
import org.jbpm.api.ProcessDefinition;
import org.jbpm.api.ProcessEngine;
import org.jbpm.api.RepositoryService;
import org.jbpm.api.TaskService;
import org.jbpm.api.cmd.Command;
import org.jbpm.api.cmd.Environment;
import org.jbpm.api.history.HistoryActivityInstance;
import org.jbpm.api.history.HistoryActivityInstanceQuery;
import org.jbpm.api.history.HistoryProcessInstance;
import org.jbpm.api.history.HistoryProcessInstanceQuery;
import org.jbpm.api.identity.User;
import org.jbpm.api.model.Activity;
import org.jbpm.api.model.Transition;
import org.jbpm.api.task.Participation;
import org.jbpm.api.task.Task;
import org.jbpm.pvm.internal.history.model.HistoryActivityInstanceImpl;
import org.jbpm.pvm.internal.history.model.HistoryProcessInstanceImpl;
import org.jbpm.pvm.internal.history.model.HistoryTaskImpl;
import org.jbpm.pvm.internal.history.model.HistoryTaskInstanceImpl;
import org.jbpm.pvm.internal.identity.impl.UserImpl;
import org.jbpm.pvm.internal.model.ExecutionImpl;
import org.jbpm.pvm.internal.query.AbstractQuery;
import org.jbpm.pvm.internal.task.ParticipationImpl;
import org.jbpm.pvm.internal.task.TaskImpl;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import com.sun.org.apache.bcel.internal.generic.ISTORE;

import pl.net.bluesoft.rnd.processtool.ProcessToolContext;
import pl.net.bluesoft.rnd.processtool.bpm.BpmEvent;
import pl.net.bluesoft.rnd.processtool.bpm.ProcessToolBpmSession;
import pl.net.bluesoft.rnd.processtool.bpm.exception.ProcessToolSecurityException;
import pl.net.bluesoft.rnd.processtool.bpm.impl.AbstractProcessToolSession;
import pl.net.bluesoft.rnd.processtool.hibernate.ResultsPageWrapper;
import pl.net.bluesoft.rnd.processtool.model.BpmTask;
import pl.net.bluesoft.rnd.processtool.model.ProcessInstance;
import pl.net.bluesoft.rnd.processtool.model.ProcessInstanceFilter;
import pl.net.bluesoft.rnd.processtool.model.ProcessInstanceLog;
import pl.net.bluesoft.rnd.processtool.model.ProcessStatus;
import pl.net.bluesoft.rnd.processtool.model.QueueType;
import pl.net.bluesoft.rnd.processtool.model.UserData;
import pl.net.bluesoft.rnd.processtool.model.config.ProcessDefinitionConfig;
import pl.net.bluesoft.rnd.processtool.model.config.ProcessStateAction;
import pl.net.bluesoft.rnd.processtool.model.config.ProcessStateConfiguration;
import pl.net.bluesoft.rnd.processtool.model.nonpersistent.MutableBpmTask;
import pl.net.bluesoft.rnd.processtool.model.nonpersistent.ProcessQueue;
import pl.net.bluesoft.rnd.pt.ext.jbpm.query.BpmTaskFilterQuery;
import pl.net.bluesoft.util.lang.Lang;
import pl.net.bluesoft.util.lang.Mapcar;
import pl.net.bluesoft.util.lang.Predicate;
import pl.net.bluesoft.util.lang.Strings;
import pl.net.bluesoft.util.lang.Transformer;

/**
* jBPM session implementation
*
* @author tlipski@bluesoft.net.pl
* @author amichalak@bluesoft.net.pl
*/
public class ProcessToolJbpmSession extends AbstractProcessToolSession
{
    private static final String AUTO_SKIP_TASK_NAME_PREFIX = "AUTO_SKIP";
  private static final String AUTO_SKIP_ACTION_NAME = "AUTO_SKIP";
  private static final String JOIN_NODE_NAME = "join";
  private static final String FORK_NODE_NAME = "fork";
  protected Logger log = Logger.getLogger(ProcessToolJbpmSession.class.getName());

    private static final Integer DEFAULT_OFFSET_VALUE = 0;
  private static final Integer DEFAULT_LIMIT_VALUE = 1000;
  protected Logger loger = Logger.getLogger(ProcessToolJbpmSession.class.getName());

    public ProcessToolJbpmSession(UserData user, Collection<String> roleNames, ProcessToolContext ctx) {
        super(user, roleNames, ctx.getRegistry());
        if (user != null) {
            IdentityService is = getProcessEngine(ctx).getIdentityService();
            User jbpmUser = is.findUserById(user.getLogin());
            if (jbpmUser == null) {
                is.createUser(user.getLogin(), user.getRealName(), user.getEmail());
            }
            getProcessEngine(ctx).setAuthenticatedUserId(user.getLogin());

        }
    }

    @Override
     public Collection<BpmTask> getAllTasks(ProcessToolContext ctx) {
       Command<List<Task>> cmd = new Command<List<Task>>() {
         @Override
         public List<Task> execute(Environment environment) throws Exception {
           AbstractQuery q = new AbstractQuery() {
             @Override
             protected void applyPage(Query query) {
             }

             @Override
             protected void applyParameters(Query query) {
             }

             @Override
             public String hql() {
               StringBuilder hql = new StringBuilder();
               hql.append("select task ");
               hql.append("from ");
               hql.append(TaskImpl.class.getName());
               hql.append(" as task  ");
               hql.append("order by task.id DESC");
               return hql.toString();
             }
           };
           return (List<Task>) q.execute(environment);
         }
       };
       List<Task> tasks = getProcessEngine(ctx).execute(cmd);
       return findProcessInstancesForTasks(tasks, ctx);
     }
   
     public Collection<BpmTask> getProcessTaskInQueues(ProcessToolContext ctx, final ProcessInstance processInstance)
     {
       Command<List<Task>> cmd = new Command<List<Task>>() {
         @Override
         public List<Task> execute(Environment environment) throws Exception {
           AbstractQuery q = new AbstractQuery() {
             @Override
             protected void applyPage(Query query)
             {

             }
            
             @Override
             protected void applyParameters(Query query)
             {
               query.setString("executionId", processInstance.getInternalId());
             }

             @Override
             public String hql() {
               StringBuilder hql = new StringBuilder();
               hql.append("select task ")
               .append("from ")
               .append(TaskImpl.class.getName()).append(" as task, ")
               .append(ParticipationImpl.class.getName()).append(" as participation ")
               .append(" where participation.task = task ")
               .append(" and task.executionId = :executionId ");
               return hql.toString();
             }
           };
           return (List<Task>) q.execute(environment);
         }
       };
       List<Task> tasks = getProcessEngine(ctx).execute(cmd);
       return findProcessInstancesForTasks(tasks, ctx);
     }

       @Override
       public BpmTask getPastEndTask(ProcessInstanceLog log, ProcessToolContext ctx) {
           final ProcessInstance pi = log.getOwnProcessInstance();
           String endTaskName = findEndActivityName(pi, ctx);
           if (Strings.hasText(endTaskName)) {
               MutableBpmTask t = new MutableBpmTask();
               t.setProcessInstance(pi);
               t.setAssignee(user.getLogin());
               t.setOwner(user);
               t.setTaskName(endTaskName);
               t.setFinished(true);
               return t;
           }
           return null;
       }

       @Override
       public BpmTask getPastOrActualTask(final ProcessInstanceLog log, ProcessToolContext ctx) {
           final UserData user = log.getUser();
           final ProcessInstance pi = log.getOwnProcessInstance();
           final Calendar minDate = log.getEntryDate();
           final Set<String> taskNames = new HashSet<String>();
           if (log.getState() != null && Strings.hasText(log.getState().getName())) {
               taskNames.add(log.getState().getName());
           }

           Command<List<HistoryActivityInstance>> cmd = new Command<List<HistoryActivityInstance>>() {
               @Override
               public List<HistoryActivityInstance> execute(Environment environment) throws Exception {
                   AbstractQuery q = new AbstractQuery() {
                       @Override
                       protected void applyPage(Query query) {
                           query.setFirstResult(0);
                           query.setMaxResults(1);
                       }

                       @Override
                       protected void applyParameters(Query query) {
                           query.setString("userIds", user.getLogin());
                           query.setString("internalIds", log.getExecutionId());
                           query.setDate("minDate", minDate.getTime());
                           if (!taskNames.isEmpty()) {
                               query.setParameterList("taskName", taskNames);
                           }
                       }

                       @Override
                       public String hql() {
                           StringBuilder hql = new StringBuilder()
                                   .append("select act ")
                                   .append("from ")
                                   .append(HistoryTaskInstanceImpl.class.getName()).append(" as act, ")
                                   .append(HistoryProcessInstanceImpl.class.getName()).append(" as proc, ")
                                   .append(HistoryTaskImpl.class.getName()).append(" as task  ")
                                   .append(" where act.historyProcessInstance = proc ")
                                   .append(" and act.historyTask = task ")
                                   .append(" and act.endTime is not null ");
                           if (!taskNames.isEmpty()) {
                               hql.append(" and act.activityName in (:taskName) ");
                           }
                           hql.append(" and task.assignee = :userIds ")
                                   .append(" and task.endTime > :minDate ")
                                   .append(" and act.executionId = :internalIds ")
                                   .append(" order by act.endTime asc ");
                           return hql.toString();
                       }
                   };
                   return (List<HistoryActivityInstance>) q.execute(environment);
               }
           };

           List<HistoryActivityInstance> pastTasks = getProcessEngine(ctx).execute(cmd);
           if (!pastTasks.isEmpty()) {
               return collectHistoryActivity(pastTasks.get(0), pi, user, ctx);
           }
           else {
               List<BpmTask> actualTasks = findProcessTasks(pi, user.getLogin(), taskNames, ctx);
               if (!actualTasks.isEmpty()) {
                   return actualTasks.get(0);
               }
           }
           return null;
       }

       @Override
     public List<BpmTask> findRecentTasks(Calendar minDate, Integer offset, Integer limit, ProcessToolContext ctx) {
       List<BpmTask> recentTasks = new ArrayList<BpmTask>();
       UserData user = getUser(ctx);
       ResultsPageWrapper<ProcessInstance> recentInstances = ctx.getProcessInstanceDAO().getRecentProcesses(user, minDate, offset, limit);
       Collection<ProcessInstance> instances = recentInstances.getResults();
       for (ProcessInstance pi : instances) {
         List<BpmTask> tasks = findProcessTasks(pi, user.getLogin(), ctx);
         if (tasks.isEmpty()) {
           BpmTask task = getMostRecentProcessHistoryTask(pi, user, minDate, ctx);
           if (task != null) {
             recentTasks.add(task);
           }
         }
         else {
           recentTasks.addAll(tasks);
         }
       }
       return recentTasks;
     }

     private BpmTask getMostRecentProcessHistoryTask(final ProcessInstance pi, final UserData user, final Calendar minDate, ProcessToolContext ctx) {
       Command<List<HistoryActivityInstance>> cmd = new Command<List<HistoryActivityInstance>>() {
         @Override
         public List<HistoryActivityInstance> execute(Environment environment) throws Exception {
           AbstractQuery q = new AbstractQuery() {
             @Override
             protected void applyPage(Query query) {
               query.setFirstResult(0);
               query.setMaxResults(1);
             }
             @Override
             protected void applyParameters(Query query) {
               query.setString("userIds", user.getLogin());
               query.setString("internalIds", pi.getInternalId());
               query.setDate("minDate", minDate.getTime());
             }
             @Override
             public String hql() {
               StringBuilder hql = new StringBuilder()
               .append("select act ")
               .append("from ")
               .append(HistoryTaskInstanceImpl.class.getName()).append(" as act, ")
               .append(HistoryProcessInstanceImpl.class.getName()).append(" as proc, ")
               .append(HistoryTaskImpl.class.getName()).append(" as task  ")
               .append(" where act.historyProcessInstance = proc ")
               .append(" and act.historyTask = task ")
               .append(" and act.endTime is not null ")
               .append(" and task.assignee = :userIds ")
               .append(" and task.endTime > :minDate ")
               .append(" and proc.processInstanceId = :internalIds ")
               .append(" order by act.endTime desc ");
               return hql.toString();
             }
           };
           return (List<HistoryActivityInstance>) q.execute(environment);
         }
       };

       List<HistoryActivityInstance> tasks = getProcessEngine(ctx).execute(cmd);
           if (tasks.isEmpty()) {
               return null;
           }
           MutableBpmTask task = collectHistoryActivity(tasks.get(0), pi, user, ctx);
           String endTaskName = findEndActivityName(pi, ctx);
           if (Strings.hasText(endTaskName)) {
               task.setTaskName(endTaskName);
           }
           return task;
     }

     @Override
     public Integer getRecentTasksCount(Calendar minDate, ProcessToolContext ctx) {
       int count = 0;
       UserData user = getUser(ctx);
       Collection<ProcessInstance> instances = ctx.getProcessInstanceDAO().getUserProcessesAfterDate(user, minDate);
       for (ProcessInstance pi : instances) {
         List<BpmTask> tasks = findProcessTasks(pi, user.getLogin(), ctx);
         if (tasks.isEmpty() && getMostRecentProcessHistoryTask(pi, user, minDate, ctx) != null) {
           count += 1;
         }
         else {
           count += tasks.size();
         }
       }
       return count;
     }
    
  @Override
  public int getTasksCount(ProcessToolContext ctx, String userLogin, QueueType... queueTypes)
  {
    return ctx.getUserProcessQueueDAO().getQueueLength(userLogin, queueTypes);
  }

  @Override
  public int getTasksCount(ProcessToolContext ctx, String userLogin, Collection<QueueType> queueTypes)
  {
    return ctx.getUserProcessQueueDAO().getQueueLength(userLogin, queueTypes);
  }
 
  @Override
  public int getFilteredTasksCount(ProcessInstanceFilter filter, ProcessToolContext ctx)
  {
       /* Initialize query */
       BpmTaskFilterQuery taskFilterQuery = new BpmTaskFilterQuery(ctx);
      
       /* Queues filter do not have owner */
       if(filter.getFilterOwner() != null)
         taskFilterQuery.addUserLoginCondition(filter.getFilterOwner().getLogin());
      
       if(!filter.getQueueTypes().isEmpty())
         taskFilterQuery.addQueueTypeCondition(filter.getQueueTypes());
      
       /* Add external conditions for process instance filter */
       addExternalConditions(taskFilterQuery, filter);
      
       /* Get results count. No entities are loaded to memory using this */
       return taskFilterQuery.getBpmTaskCount();
  }
    
    
  public List<BpmTask> findFilteredTasks(ProcessInstanceFilter filter, ProcessToolContext ctx)
  {
    return findFilteredTasks(filter, ctx, 0, 0);
  }
    
  public List<BpmTask> findFilteredTasks(ProcessInstanceFilter filter, ProcessToolContext ctx, int offset, int maxResults)
     {
       /* Initialize query */
       BpmTaskFilterQuery taskFilterQuery = new BpmTaskFilterQuery(ctx);
      
       /* Queues filter do not have owner */
       if(filter.getFilterOwner() != null)
         taskFilterQuery.addUserLoginCondition(filter.getFilterOwner().getLogin());
      
       if(!filter.getQueueTypes().isEmpty())
         taskFilterQuery.addQueueTypeCondition(filter.getQueueTypes());
      
       /* Set limit for max results count */
       taskFilterQuery.setMaxResultsLimit(maxResults);
       taskFilterQuery.setResultsOffset(offset);
       /* Add external conditions for process instance filter */
       addExternalConditions(taskFilterQuery, filter);
      
    /* BpmTasks */
    List<BpmTask> result = taskFilterQuery.getBpmTasks();
      
       return result;
     }
    
     /** Add additional conditions to query from process instance filter */
     private void addExternalConditions(BpmTaskFilterQuery taskFilterQuery,ProcessInstanceFilter filter)
     {
       /* Prepare data for owner lists and not owner list */
       Collection<String> ownerNames = new HashSet<String>();
       for(UserData userData: filter.getOwners())
         ownerNames.add(userData.getLogin());
      
       /* Add condition for task names if any exists */
       if(!filter.getTaskNames().isEmpty())
         taskFilterQuery.addTaskNamesCondtition(filter.getTaskNames());
      
       /* Add conidtion for created before date */
       if(filter.getCreatedBefore() != null)
         taskFilterQuery.addCreatedBeforeCondition(filter.getCreatedBefore());
      
       /* Add conidtion for created after date */
       if(filter.getCreatedAfter() != null)
         taskFilterQuery.addCreatedAfterCondition(filter.getCreatedAfter());
      
       if(!filter.getQueues().isEmpty())
         taskFilterQuery.addQueuesCondition(filter.getQueues());
      
       /* Add condition for owner */
       if(!ownerNames.isEmpty())
         taskFilterQuery.addOwnerLoginsCondtition(ownerNames);
     }
    
//     /** Prepare hql query using given filter */
//     private ProcessEngineQuery<HistoryTaskInstanceImpl> prepareTaskQuery(ProcessInstanceFilter filter)
//     {
//       /* Create process engine query */
//       ProcessEngineQuery<HistoryTaskInstanceImpl> processEngineQuery = new ProcessEngineQuery<HistoryTaskInstanceImpl>();
//
//       Collection<String> ownerNames = new HashSet<String>();
//       for(UserData userData: filter.getOwners())
//         ownerNames.add(userData.getLogin());
//
//
//       /* Prepare hql statement */
//    StringBuilder hql = new StringBuilder();
//    hql.append("SELECT act ");
//    hql.append("FROM ");
//    hql.append(HistoryTaskInstanceImpl.class.getName()).append(" as act ");
//    hql.append("left join fetch act.historyTask ").append(" as task  ");
//    hql.append(", ").append(HistoryProcessInstanceImpl.class.getSimpleName()).append(" as proc ");
//
//    if (!filter.getQueues().isEmpty()) {
//      hql.append(", ");
//      hql.append(ParticipationImpl.class.getName());
//      hql.append(" AS participant ");
//      hql.append("WHERE participant.task=task ");
//      hql.append("AND participant.type = 'candidate' ");
//      hql.append("AND participant.groupId IN (:groupIds) ");
//      hql.append("AND task.assignee IS null ");
//      hql.append(" AND ");
//    }
//    else {
//      hql.append(" WHERE ");
//    }
//    hql.append(" act.historyProcessInstance = proc ");
//    hql.append(" and act.historyTask = task ");
//
//    if(filter.getQueueTypes().contains(QueueType.OWN_FINISHED))
//      hql.append(" and proc.state = 'ended' ");
//    else
//      hql.append(" and proc.state = 'active' ");
//
//    StringBuffer hqltmp = new StringBuffer();
//    hqltmp.append(" NOT EXISTS (SELECT 1 FROM ").append(HistoryTaskInstanceImpl.class.getName()).append(" as act1 WHERE act.historyProcessInstance = act1.historyProcessInstance AND act1.dbid > act.dbid) ");
//
//    if (!filter.getTaskNames().isEmpty()) {
//      hql.append(" AND act.activityName IN (:taskNames) ");
//    }
//    if (!ownerNames.isEmpty()) {
//      hql.append(" AND task.assignee IN (:ownerIds) ");
//    }
//
//    hql.append("order by task.id DESC");
//
//    /* Set prepared query */
//    processEngineQuery.setQuery(hql.toString());
//
//    /* Add parameters for query */
//    if (!filter.getQueues().isEmpty())
//      processEngineQuery.addListParameter("groupIds", filter.getQueues());
//
//    if (!ownerNames.isEmpty())
//      processEngineQuery.addListParameter("ownerIds", ownerNames);
//
//
//    if (!filter.getTaskNames().isEmpty())
//      processEngineQuery.addListParameter("taskNames", filter.getTaskNames());
//
//    return processEngineQuery;
//     }

     protected ProcessEngine getProcessEngine(ProcessToolContext ctx) {
       if (ctx instanceof ProcessToolContextImpl) {
         ProcessEngine engine = ((ProcessToolContextImpl) ctx).getProcessEngine();
         if (user != null && user.getLogin() != null) {
           engine.setAuthenticatedUserId(user.getLogin());
         }
         return engine;
       }
       else {
         throw new IllegalArgumentException(ctx + " not an instance of " + ProcessToolContextImpl.class.getName());
       }
     }

     @Override
     public Collection<ProcessQueue> getUserAvailableQueues(ProcessToolContext ctx) { 
       Collection<ProcessQueue> configs = getUserQueuesFromConfig(ctx)
       final List<String> names = keyFilter("name", configs);
       if (names.isEmpty()) {
         return new ArrayList<ProcessQueue>()
       }
       Command<List<Map>> cmd = new Command<List<Map>>() {
         @Override
         public List<Map> execute(Environment environment) throws Exception {
           return (List<Map>) new AbstractQuery() {
             @Override
             protected void applyParameters(Query query) {
               query.setParameterList("groupIds", names);
             }

             @Override
             public String hql() {
               return new StringBuilder()
               .append("select new map(participant.groupId as groupId, count(task) as taskCount) ")
               .append("from ")
               .append(TaskImpl.class.getName())
               .append(" as task ")
               .append(", ")
               .append(ParticipationImpl.class.getName())
               .append(" as participant ")
               .append("where participant.task=task ")
               .append("and participant.type = 'candidate' ")
               .append("and participant.groupId IN (:groupIds) ")
               .append("and task.assignee is null ")
               .append("group by participant.groupId")
               .toString();
             }
           }.execute(environment);
         }
       };

       List<Map> maps = getProcessEngine(ctx).execute(cmd);
       Map<String, Long> counts = new HashMap<String, Long>();
       for (Map m : maps) {
         counts.put((String) m.get("groupId"), (Long) m.get("taskCount"));
       }

       for (ProcessQueue q : configs) {
         q.setProcessCount(nvl(counts.get(q.getName()), (long) 0));
       }
       return configs;
     }
    
  @SuppressWarnings("unchecked")
  @Override
  public List<BpmTask> getQueueTasks(ProcessToolContext ctx, String queueName)
  {
    SQLQuery query = ctx.getHibernateSession().createSQLQuery(
        "select task.*, process.*, part.* from jbpm4_task task, pt_process_instance process, jbpm4_participation part " +
        "where process.internalid = task.execution_id_ and part.task_ = task.dbid_ " +
        "and part.groupid_ = '"+queueName+"'");
   
    query.addEntity("task", TaskImpl.class);
    query.addEntity("process", ProcessInstance.class);
    query.addEntity("part", ParticipationImpl.class);
   
    /* Get query results */
    List<Object[]> queueResults = query.list();
   
    List<BpmTask> result = new ArrayList<BpmTask>();
   
    BpmTaskFactory taskFactory = new BpmTaskFactory(ctx);
   
    /* Every row is one queue element with jbpm task as first column and process instance as second */
       for(Object[] resultRow: queueResults)
       {
        
         TaskImpl taskInstance = (TaskImpl)resultRow[0];
         ProcessInstance processInstance = (ProcessInstance)resultRow[1];
        
         /* Map process and jbpm task to system's bpm task */
         BpmTask task = taskFactory.create(taskInstance, processInstance);
        
         result.add(task);
       }
      
       return result;
  }
 

     @Override
     public BpmTask assignTaskFromQueue(ProcessQueue queue, ProcessToolContext ctx) {
       return assignTaskFromQueue(queue, null, ctx);
     }

    @Override
    public BpmTask assignTaskFromQueue(final ProcessQueue pq, BpmTask bpmTask, ProcessToolContext ctx) {
        Collection<ProcessQueue> configs = getUserQueuesFromConfig(ctx);
        final List<String> names = keyFilter("name", configs);
        if (!names.contains(pq.getName())) {
            throw new ProcessToolSecurityException("queue.no.rights", pq.getName());
        }

        ProcessEngine processEngine = getProcessEngine(ctx);

        final String taskId = bpmTask != null ? bpmTask.getInternalTaskId() : null;
        Command<List<Task>> cmd = new Command<List<Task>>() {
            @Override
            public List<Task> execute(Environment environment) throws Exception {
                AbstractQuery q = new AbstractQuery() {
                    @Override
                    protected void applyPage(Query query) {
                        query.setFirstResult(0);
                        query.setFetchSize(1);
                    }

                    @Override
                    protected void applyParameters(Query query) {
                        query.setParameterList("groupIds", java.util.Collections.singleton(pq.getName()));
                        if (taskId != null) {
                            query.setParameter("taskId", new Long(taskId));
                        }
                    }

                    @Override
                    public String hql() {
                        StringBuilder hql = new StringBuilder();
                        hql.append("select task ");
                        hql.append("from ");
                        hql.append(TaskImpl.class.getName());
                        hql.append(" as task ");
                        hql.append(", ");
                        hql.append(ParticipationImpl.class.getName());
                        hql.append(" as participant ");
                        hql.append("where participant.task=task ");
                        hql.append("and participant.type = 'candidate' ");
                        hql.append("and participant.groupId IN (:groupIds) ");
                        hql.append("and task.assignee is null ");
                        if (taskId != null) {
                            hql.append("and task.id = :taskId");
                        }
                        return hql.toString();
                    }
                };
                return (List<Task>) q.execute(environment);
            }
        };
        List<Task> taskList = processEngine.execute(cmd);
        if (taskList.isEmpty()) {
            loger.warning("No tasks found in queue: " + pq.getName());
            return null;
        }
        Task task = taskList.get(0);
        Execution exec = processEngine.getExecutionService().findExecutionById(task.getExecutionId());
        String internalId = exec.getProcessInstance().getId();
        ProcessInstance pi = getProcessData(internalId, ctx);
        if (pi == null) {
            loger.warning("Process instance not found for instance id: " + internalId);
            return null;
        }

        Calendar snapshotDate = Calendar.getInstance();

        processEngine.getTaskService().assignTask(task.getId(), user.getLogin());
        task = processEngine.getTaskService().getTask(task.getId());
        if (!user.getLogin().equals(task.getAssignee())) {
            loger.warning("Task: + " + bpmTask.getExecutionId() + " not assigned to requesting user: " + user.getLogin());
            return null;
        }

        ProcessInstanceLog log = new ProcessInstanceLog();
        log.setLogType(ProcessInstanceLog.LOG_TYPE_CLAIM_PROCESS);

        ctx.getProcessInstanceDAO().saveProcessInstance(pi);
        bpmTask = collectTask(task, pi, ctx);
        log.setState(ctx.getProcessDefinitionDAO().getProcessStateConfiguration(bpmTask));
        log.setEntryDate(snapshotDate);
        log.setEventI18NKey("process.log.process-assigned");
        log.setLogValue(pq.getName());
        log.setUser(findOrCreateUser(user, ctx));
        log.setAdditionalInfo(pq.getDescription());
        log.setExecutionId(task.getExecutionId());
        log.setOwnProcessInstance(pi);
        pi.getRootProcessInstance().addProcessLog(log);

        if (!ProcessStatus.RUNNING.equals(pi.getStatus())) {
            pi.setStatus(ProcessStatus.RUNNING);
        }
       
    /* Inform queue manager about task assigne */
    ctx.getUserProcessQueueManager().onTaskAssigne(bpmTask);
   
        broadcastEvent(ctx, new BpmEvent(BpmEvent.Type.ASSIGN_TASK, bpmTask, user));
        broadcastEvent(ctx, new ViewEvent(ViewEvent.Type.ACTION_COMPLETE));

        return bpmTask;
    }

     private List<BpmTask> collectTasks(List<Task> tasks, final ProcessInstance pi, final ProcessToolContext ctx) {
      
      
       return new Mapcar<Task, BpmTask>(tasks) {
         @Override
         public BpmTask lambda(Task x) {
           return collectTask(x, pi, ctx);  
         }
       }.go();
     }

     private MutableBpmTask collectHistoryActivity(HistoryActivityInstance task, ProcessInstance pi, UserData user, ProcessToolContext ctx) {
       MutableBpmTask t = new MutableBpmTask();
       t.setProcessInstance(pi);
       t.setAssignee(user.getLogin());
       t.setOwner(user);
       t.setTaskName(task.getActivityName());
       t.setInternalTaskId(null);
       t.setExecutionId(task.getExecutionId());
       t.setCreateDate(task.getStartTime());
       t.setFinishDate(task.getEndTime());
       t.setFinished(task.getEndTime() != null);
       return t;
     }
    
    
    

     /** Get the last step name of the process */
    private String findEndActivityName(ProcessInstance pi, ProcessToolContext ctx)
    {
      /* Get all history activities for given process and order it by the end date */
      List<HistoryActivityInstance> activities = getProcessEngine(ctx).getHistoryService().createHistoryActivityInstanceQuery()
          .processInstanceId(pi.getInternalId())
          .orderDesc(HistoryActivityInstanceQuery.PROPERTY_ENDTIME)
          .list();
     
      /* Looking for specific activity, becouse if there is a for-each statment in process, there
       * might be a problem with correct end task name
       */
        if (activities != null && !activities.isEmpty())
        {
          for(HistoryActivityInstance activity: activities)
          {
            if(activity instanceof HistoryActivityInstanceImpl)
            {
              HistoryActivityInstanceImpl activityImpl = (HistoryActivityInstanceImpl)activity;
              /* There are trasictions and xors, we are interested in only with tasks */
              if(activityImpl.getType().equals("task"))
                return activityImpl.getActivityName();
            }
          }
           
        }
        return null;
    }

    private MutableBpmTask collectTask(Task task, ProcessInstance pi, ProcessToolContext ctx) {
       MutableBpmTask t = new MutableBpmTask();
       t.setProcessInstance(pi);
       t.setAssignee(task.getAssignee());
       UserData ud = ctx.getUserDataDAO().loadUserByLogin(task.getAssignee());
       if (ud == null) {
         ud = new UserData();
         ud.setLogin(task.getAssignee());
       }
       t.setOwner(ud);
       t.setTaskName(task.getActivityName());
       t.setInternalTaskId(task.getId());
       t.setExecutionId(task.getExecutionId());
       t.setCreateDate(task.getCreateTime());
       t.setFinished(false);
       return t;
     }

     @Override
     public BpmTask getTaskData(String taskId, ProcessToolContext ctx) {
       Task task = getProcessEngine(ctx).getTaskService().getTask(taskId);
       if (task == null) {
         return null;
       }
       List<BpmTask> tasks = findProcessInstancesForTasks(java.util.Collections.singletonList(task), ctx);
       return tasks.isEmpty() ? null : tasks.get(0);
     }

     @Override
     public List<BpmTask> getTaskData(String taskExecutionId, String taskName, ProcessToolContext ctx) {
      
      long start = System.currentTimeMillis();
       List<Task> tasks = getProcessEngine(ctx).getTaskService().createTaskQuery()
           .notSuspended()
           .activityName(taskName)
           .executionId(taskExecutionId)
           .page(0, 1)
           .list();
       if (tasks.isEmpty()) {
         loger.warning("Task " + taskExecutionId + " not found");
         return null;
       }
       List<BpmTask> bpmTasks = findProcessInstancesForTasks(tasks, ctx);
      
      long duration = System.currentTimeMillis() - start;
    log.severe("getTaskData: " +  duration);
       return bpmTasks;
     }

     @Override
     public BpmTask refreshTaskData(BpmTask task, ProcessToolContext ctx) {
       MutableBpmTask bpmTask = task instanceof MutableBpmTask ? (MutableBpmTask) task : new MutableBpmTask(task);
       bpmTask.setProcessInstance(getProcessData(task.getProcessInstance().getInternalId(), ctx));
       List<Task> tasks = getProcessEngine(ctx).getTaskService().createTaskQuery()
           .notSuspended()
           .activityName(task.getTaskName())
           .executionId(task.getExecutionId())
           .assignee(user.getLogin())
           .page(0, 1)
           .list();
       if (tasks.isEmpty()) {
         loger.warning("Task " + task.getExecutionId() + " not found");
         bpmTask.setFinished(true);
       }
       return bpmTask;
     }

       @Override
       public List<BpmTask> findProcessTasks(ProcessInstance pi,
                                             final String userLogin,
                                             final Set<String> taskNames,
                                             ProcessToolContext ctx) {
           final Map<String, Execution> executions = getActiveExecutions(pi.getInternalId(), ctx);
           if (executions.isEmpty()) {
               return new ArrayList<BpmTask>();
           }
           Command<List<Task>> cmd = new Command<List<Task>>() {
               @Override
               public List<Task> execute(Environment environment) throws Exception {
                   AbstractQuery q = new AbstractQuery() {
                       @Override
                       protected void applyPage(Query query) {
                           query.setFirstResult(0);
                       }

                       @Override
                       protected void applyParameters(Query query) {
                           query.setParameterList("executionId", executions.keySet());
                           if (userLogin != null) {
                               query.setParameterList("userLogin", java.util.Collections.singleton(userLogin));
                           }
                           if (taskNames != null && !taskNames.isEmpty()) {
                               query.setParameterList("taskNames", taskNames);
                           }
                       }

                       @Override
                       public String hql() {
                           StringBuilder hql = new StringBuilder();
                           hql.append("select task ");
                           hql.append("from ");
                           hql.append(TaskImpl.class.getName());
                           hql.append(" as task ");
                           hql.append("where executionId in (:executionId) ");
                           hql.append("and task.assignee ");
                           hql.append(userLogin != null ? " in (:userLogin) " : " is not null ");
                           if (taskNames != null && !taskNames.isEmpty()) {
                               hql.append("and task.name in (:taskNames) ");
                           }
                           return hql.toString();
                       }
                   };
                   return (List<Task>) q.execute(environment);
               }
           };
           List<Task> tasks = getProcessEngine(ctx).execute(cmd);
           return collectTasks(tasks, pi, ctx);
       }

       @Override
       public List<BpmTask> findProcessTasks(ProcessInstance pi, final String userLogin, ProcessToolContext ctx) {
           return findProcessTasks(pi, userLogin, null, ctx);
       }
       @Override
     public List<BpmTask> findProcessTasksWithUser(ProcessInstance pi, ProcessToolContext ctx) {
         long start = System.currentTimeMillis();
         List<BpmTask> findProcessTasks;  
         if(user!=null){
         findProcessTasks = findProcessTasks(pi, user.getLogin(), ctx);
        }
         else{
          
          findProcessTasks = findProcessTasks(pi, null, ctx);
         }
        long duration = System.currentTimeMillis() - start;
      log.severe("findProcessTasks: " +  duration);
       
        return findProcessTasks;
     }
      
       public  List<BpmTask> findProcessTasks(ProcessInstance pi, ProcessToolContext ctx) {
            long start = System.currentTimeMillis();
            List<BpmTask> findProcessTasks;
             findProcessTasks = findProcessTasks(pi, null, ctx);
           long duration = System.currentTimeMillis() - start;
         log.severe("findProcessTasks: " +  duration);
          
           return findProcessTasks;
        }

     @Override
     public boolean isProcessOwnedByUser(final ProcessInstance processInstance, ProcessToolContext ctx) {
      
      long start = System.currentTimeMillis();
       final Map<String, Execution> executions = getActiveExecutions(processInstance.getInternalId(), ctx);
       if (executions.isEmpty()) {
         return false;
       }
       Command<List<Task>> cmd = new Command<List<Task>>() {
         @Override
         public List<Task> execute(Environment environment) throws Exception {
           AbstractQuery q = new AbstractQuery() {
             @Override
             protected void applyPage(Query query) {
               query.setFirstResult(0);
               query.setMaxResults(1);
             }

             @Override
             protected void applyParameters(Query query) {
               query.setParameterList("executionId", executions.keySet());
               query.setParameterList("assignee", java.util.Collections.singleton(user.getLogin()));
             }

             @Override
             public String hql() {
               StringBuilder hql = new StringBuilder();
               hql.append("select task ");
               hql.append("from ");
               hql.append(TaskImpl.class.getName());
               hql.append(" as task ");
               hql.append("where executionId in (:executionId) ");
               hql.append("and task.assignee in (:assignee) ");
               return hql.toString();
             }
           };
           return (List<Task>) q.execute(environment);
         }
       };
       List<Task> tasks = getProcessEngine(ctx).execute(cmd);
      
       long duration = System.currentTimeMillis() - start;
    log.severe("isProcessOwnedByUser: " +  duration);
       return !tasks.isEmpty();
     }

     @Override
     public List<BpmTask> findUserTasks(Integer offset, Integer limit, final ProcessToolContext ctx) {
      
      long start = System.currentTimeMillis();
       if(limit== null){
        
         limit=DEFAULT_LIMIT_VALUE;
       }
       if(offset== null){
         offset=DEFAULT_OFFSET_VALUE;
        
       }
       List<Task> tasks = getProcessEngine(ctx).getTaskService().createTaskQuery()
           .notSuspended()
           .assignee(user.getLogin())
           .page(offset, limit)
           .list();
        List<BpmTask> processInstancesForTasks = findProcessInstancesForTasks(tasks, ctx);
       
        long duration = System.currentTimeMillis() - start;
      log.severe("findUserTasks: " +  duration);
       
        return processInstancesForTasks;
     }

     private List<BpmTask> findProcessInstancesForTasks(List<Task> tasks, final ProcessToolContext ctx) {
       Map<String, List<Task>> tasksByProcessId = pl.net.bluesoft.util.lang.Collections.group(tasks, new Transformer<Task, String>() {
               @Override
               public String transform(Task task) {
                   Execution exec = getProcessEngine(ctx).getExecutionService().findExecutionById(task.getExecutionId());
                   return exec.getProcessInstance().getId();
               }
           });
       final Map<String, ProcessInstance> instances = ctx.getProcessInstanceDAO().getProcessInstanceByInternalIdMap(tasksByProcessId.keySet());
       final List<BpmTask> result = new ArrayList<BpmTask>();
    for (Map.Entry<String, List<Task>> entry : tasksByProcessId.entrySet()) {
      final String processId = entry.getKey();
      List<Task> processTasks = entry.getValue();

         result.addAll(new Mapcar<Task, BpmTask>(processTasks) {
           @Override
           public BpmTask lambda(Task task) {
             ProcessInstance pi = instances.get(processId);
             if (pi == null) {
               loger.warning("process " + processId + " not found");
               return null;
             }
             return collectTask(task, pi, ctx);
           }
         }.go());
       }
       java.util.Collections.sort(result, new Comparator<BpmTask>() {
               @Override
               public int compare(BpmTask o1, BpmTask o2) {
                   return o2.getCreateDate().compareTo(o1.getCreateDate());
               }
           });
       return result;
     }

     @Override
     public List<BpmTask> findUserTasks(final ProcessInstance processInstance, ProcessToolContext ctx) {
       final Map<String, Execution> executions = getActiveExecutions(processInstance.getInternalId(), ctx);
       if (executions.isEmpty()) {
         return new ArrayList<BpmTask>();
       }
       Command<List<Task>> cmd = new Command<List<Task>>() {
         @Override
         public List<Task> execute(Environment environment) throws Exception {
           AbstractQuery q = new AbstractQuery() {
             @Override
             protected void applyPage(Query query) {
               query.setFirstResult(0);
             }

             @Override
             protected void applyParameters(Query query) {
               query.setParameterList("executionId", executions.keySet());
               query.setParameterList("assignee", java.util.Collections.singleton(user.getLogin()));
             }

             @Override
             public String hql() {
               StringBuilder hql = new StringBuilder();
               hql.append("select task ");
               hql.append("from ");
               hql.append(TaskImpl.class.getName());
               hql.append(" as task ");
               hql.append("where executionId in (:executionId) ");
               hql.append("and task.assignee in (:assignee) ");
               return hql.toString();
             }
           };
           return (List<Task>) q.execute(environment);
         }
       };
       List<Task> tasks = getProcessEngine(ctx).execute(cmd);
       return collectTasks(tasks, processInstance, ctx);
     }

 
    
    
  @Override
    public BpmTask performAction(ProcessStateAction action, BpmTask task, ProcessToolContext ctx)
     {
           BpmTask bpmTask = getTaskData(task.getInternalTaskId(), ctx);

          
           if (bpmTask == null || bpmTask.isFinished())

               return bpmTask;
          
           ProcessInstance processInstance = bpmTask.getProcessInstance();
           ProcessInstanceLog log = addActionLogEntry(action, task, ctx);
           Map<String, Object> vars = new HashMap<String, Object>();
           vars.put("ACTION", action.getBpmName());
           processInstance.setSimpleAttribute("ACTION", action.getBpmName());
           List<String> outgoingTransitionNames = getOutgoingTransitionNames(task.getInternalTaskId(), ctx);

           ProcessEngine processEngine = getProcessEngine(ctx);

           Task bpmTaskInstance = processEngine.getTaskService().getTask(task.getInternalTaskId());
           String executionId = bpmTaskInstance.getExecutionId();


           Set<String> taskIdsBeforeCompletion = new HashSet<String>();

           pl.net.bluesoft.util.lang.Collections.collect(findProcessTasksWithUser(processInstance, ctx), new Transformer<BpmTask, String>() {

               @Override
               public String transform(BpmTask obj) {
                   return obj.getInternalTaskId()
               }
           }, taskIdsBeforeCompletion);

          
          
          if (outgoingTransitionNames.size() == 1)
              processEngine.getTaskService().completeTask(task.getInternalTaskId(), outgoingTransitionNames.get(0), vars); //BPMN2.0 style, decision is taken on the XOR gateway
          else
              processEngine.getTaskService().completeTask(task.getInternalTaskId(), action.getBpmName(), vars);
         
          broadcastEvent(ctx, new BpmEvent(BpmEvent.Type.TASK_FINISHED, task, user));
         
       /* Inform queue manager about task finish and process state change */
       ctx.getUserProcessQueueManager().onTaskFinished(task);        
  
          String processState = getProcessState(processInstance, ctx);
         
          /* Check if new subProcess is created */
          boolean startsSubprocess = updateSubprocess(processInstance, executionId, ctx);

          fillProcessAssignmentData(processEngine, processInstance, ctx);
          processInstance.setState(processState);
          if (startsSubprocess == false && processState == null && processInstance.getRunning() && !isProcessRunning(processInstance.getInternalId(), ctx)) {
              processInstance.setRunning(false);
          }
         
         
         
           if (log.getUserSubstitute() == null)
               broadcastEvent(ctx, new BpmEvent(BpmEvent.Type.SIGNAL_PROCESS, bpmTask, user));
           else
               broadcastEvent(ctx, new BpmEvent(BpmEvent.Type.SIGNAL_PROCESS, bpmTask, log.getUserSubstitute()));

           if (Strings.hasText(action.getAssignProcessStatus())) {
               String processStatus = action.getAssignProcessStatus();
               ProcessStatus ps = processStatus.length() == 1 ? ProcessStatus.fromChar(processStatus.charAt(0)) : ProcessStatus.fromString(processStatus);
               processInstance.setStatus(ps);
           }
           else
           {
             boolean isProcessRunning = processInstance.isProcessRunning();
             //boolean isProcessRunning = isProcessRunning(pi.getInternalId(), ctx);
            
             /* Process is not running and no new suprocesses are created, so process should
              * be finished by now
              */
             if(!isProcessRunning && !startsSubprocess)
             {
               broadcastEvent(ctx, new BpmEvent(BpmEvent.Type.END_PROCESS, bpmTask, user));
              
               /* Inform queue manager about process ending. Only main process is stored */
               if(!processInstance.isSubprocess())
                 ctx.getUserProcessQueueManager().onProcessFinished(processInstance, bpmTask);
              
               processInstance.setStatus(ProcessStatus.FINISHED);
             }
            
             /* Process is running or is halted, but new subprocess are created */
             else if(!isProcessRunning && startsSubprocess
             {
               broadcastEvent(ctx, new BpmEvent(BpmEvent.Type.PROCESS_HALTED, bpmTask, user));
              
               /* Inform queue manager about process halt */
               ctx.getUserProcessQueueManager().onProcessHalted(processInstance, bpmTask);
              
               processInstance.setStatus(ProcessStatus.RUNNING);
             }
             else
             {
               processInstance.setStatus(ProcessStatus.RUNNING);
             }
           }
          
           ctx.getProcessInstanceDAO().saveProcessInstance(processInstance);

           BpmTask userTask = null;

           BpmTask autoSkipTask = null;
          
           /* Is process finished */
           boolean isProcessFinished = processInstance.getStatus().equals(ProcessStatus.FINISHED);
           boolean isSubProcess = processInstance.getParent() != null;

           List<BpmTask> tasksAfterCompletion = null;
           if(startsSubprocess && processInstance.getChildren() != null) {
             for(ProcessInstance child : processInstance.getChildren()) {
               tasksAfterCompletion = findProcessTasks(child, ctx);
               if(tasksAfterCompletion != null && tasksAfterCompletion.size() > 0)
                 break;
             }
           }
           if(tasksAfterCompletion == null || tasksAfterCompletion.size() == 0) {
               tasksAfterCompletion = findProcessTasks(processInstance, ctx);
           }
           if(processInstance.getParent() != null && (tasksAfterCompletion == null || tasksAfterCompletion.size() == 0)) {
               tasksAfterCompletion = findProcessTasks(processInstance.getParent(), ctx);
           }
           if(tasksAfterCompletion != null) {
             for (BpmTask createdTask : tasksAfterCompletion) {
                 if (!taskIdsBeforeCompletion.contains(createdTask.getInternalTaskId()))
                 {
                     broadcastEvent(ctx, new BpmEvent(BpmEvent.Type.ASSIGN_TASK, createdTask, user));
                    
                 /* Inform queue manager about task assigne */
                 ctx.getUserProcessQueueManager().onTaskAssigne(createdTask);
                 }
                 if (Lang.equals(user.getId(), createdTask.getOwner().getId())) {
                     userTask = createdTask;
                 }
                 if(createdTask.getTaskName().toLowerCase().startsWith(AUTO_SKIP_TASK_NAME_PREFIX.toLowerCase())) {
                   autoSkipTask = createdTask;
                 }
             }
           }
          
           if(autoSkipTask != null) {
             ProcessStateAction skipAction = new ProcessStateAction();
             skipAction.setBpmName(AUTO_SKIP_ACTION_NAME);
             return performAction(skipAction, autoSkipTask, ctx);
           }
          
           /* Task assigned to queue */
           if (userTask == null)
           {
             /* Process is finished, ask about parent process queues */
             if(isProcessFinished && isSubProcess)
               processInstance = processInstance.getParent();
            
             /* Get task assigned to queues */
             Collection<BpmTask> queueTasks = getProcessTaskInQueues(ctx, processInstance);
            
             for(BpmTask queueTask: queueTasks)
             {
               MutableBpmTask mutableTask = new MutableBpmTask(queueTask);
               mutableTask.setAssignee(task.getAssignee());
               mutableTask.setProcessInstance(processInstance);
              
               /* Inform queue manager about task assigne */
               ctx.getUserProcessQueueManager().onQueueAssigne(mutableTask);
             }
            
               MutableBpmTask mutableTask = new MutableBpmTask(task);
               mutableTask.setFinished(true);
               mutableTask.setProcessInstance(processInstance);
               userTask = mutableTask;
           }

           broadcastEvent(ctx, new ViewEvent(ViewEvent.Type.ACTION_COMPLETE));
          
           return userTask;
          
          
       }

    @Override
     public boolean isProcessRunning(String internalId, ProcessToolContext ctx) {
     
      long start = System.currentTimeMillis();
       if (internalId == null) {
         return false;
       }
       ExecutionService service = getProcessEngine(ctx).getExecutionService();
       org.jbpm.api.ProcessInstance processInstance = service.findProcessInstanceById(internalId);
      
      long duration = System.currentTimeMillis() - start;
    log.severe("isProcessRunning: " +  duration);
   
   
       return processInstance != null && !processInstance.isEnded();
     }

    @Override
     protected ProcessInstance startProcessInstance(ProcessDefinitionConfig config, String externalKey, ProcessToolContext ctx, ProcessInstance pi) {
       final ExecutionService execService = getProcessEngine(ctx).getExecutionService();
       Map vars = new HashMap();
       vars.put("processInstanceId", String.valueOf(pi.getId()));
       vars.put("initiator", user.getLogin());

       org.jbpm.api.ProcessInstance instance = execService.startProcessInstanceByKey(config.getBpmDefinitionKey(), vars, externalKey);
       pi.setInternalId(instance.getId());

      
       return pi;
     }

     @Override
     public ProcessToolBpmSession createSession(UserData user, Collection<String> roleNames, ProcessToolContext ctx) {
       ProcessToolJbpmSession session = new ProcessToolJbpmSession(user, roleNames, ctx);
       session.substitutingUser = this.user;
       session.substitutingUserEventBusManager = this.eventBusManager;
       return session;
     }

     @Override
     public void assignTaskToUser(ProcessToolContext ctx, String taskId, String userLogin) {
      long start = System.currentTimeMillis();
       ProcessEngine processEngine = getProcessEngine(ctx);
       processEngine.getTaskService().assignTask(taskId, userLogin);
       BpmTask taskData = getTaskData(taskId, ctx);
       UserData newUser = new UserData()
       newUser.setLogin(userLogin);
       UserData loadOrCreateUser = loadOrCreateUser(ctx,newUser);
       broadcastEvent(ctx, new BpmEvent(BpmEvent.Type.ASSIGN_TASK, taskData, loadOrCreateUser));
       broadcastEvent(ctx, new BpmEvent(BpmEvent.Type.ASSIGN_TASK, taskData, user));
    ctx.getUserProcessQueueManager().onTaskAssigne(taskData);
      long duration = System.currentTimeMillis() - start;
    log.severe("assignTaskToUser: " +  duration);
     }

     protected Map<String, Execution> getActiveExecutions(String internalId, ProcessToolContext ctx) {
       Execution exec = getProcessEngine(ctx).getExecutionService().findExecutionById(internalId);
       if (exec == null) {
         loger.warning("Unable to find execution by process internal id: " + internalId);
         return new HashMap<String, Execution>();
       }
       Collection<Execution> executions = getActiveExecutions(exec, new Predicate<Execution>() {
               @Override
               public boolean apply(Execution exec) {
                   return Execution.STATE_ACTIVE_ROOT.equals(exec.getState()) || Execution.STATE_ACTIVE_CONCURRENT.equals(exec.getState());
               }
           });
       return pl.net.bluesoft.util.lang.Collections.transform(executions, new Transformer<Execution, String>() {
               @Override
               public String transform(Execution obj) {
                   return obj.getId();
               }
           });
     }

     private Collection<Execution> getActiveExecutions(Execution exec, Predicate<Execution> predicate) {
       Collection<Execution> result = new ArrayList<Execution>();
       if (predicate.apply(exec)) {
         result.add(exec);
       }
       else {
         Collection<? extends Execution> executions = exec.getExecutions();
         if (executions != null && !executions.isEmpty()) {
           for (Execution e : executions) {
             result.addAll(getActiveExecutions(e, predicate));
           }
         }
       }
       return result;
     }



////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    public List<String> getOutgoingTransitionNames(String internalId, ProcessToolContext ctx) {
        ProcessEngine engine = getProcessEngine(ctx);
        return new ArrayList<String>(engine.getTaskService().getOutcomes(internalId));
    }

    public boolean updateSubprocess(final ProcessInstance parentPi, String executionId, ProcessToolContext ctx) {
        ProcessEngine engine = getProcessEngine(ctx);
        ExecutionService executionService = engine.getExecutionService();
    Execution jbpmPi = executionService.findExecutionById(executionId);
        if(jbpmPi != null){
          Execution subprocess = jbpmPi.getSubProcessInstance();
          if(subprocess != null){
            ctx.getHibernateSession().refresh(subprocess);
           
            if (ctx.getProcessInstanceDAO().getProcessInstanceByInternalId(subprocess.getId()) == null)
            {
          String processDefinitionId = subprocess.getProcessDefinitionId().replaceFirst("-\\d+$", "");
          ProcessDefinitionConfig config = ctx.getProcessDefinitionDAO().getActiveConfigurationByKey(
              processDefinitionId);

          /* Create new instance of parent process' subprocess */
          ProcessInstance subProcessInstance = createSubprocessInstance(config, ctx, parentPi, "parent_process", subprocess.getId());
           
          long subPiId = ctx.getProcessInstanceDAO().saveProcessInstance(subProcessInstance);
         
          executionService.createVariable(subprocess.getId(), "processInstanceId", String.valueOf(subPiId),
              false);
         
          return true;
        }
          }
        }
        return false;
    }



  public List<String> getOutgoingTransitionDestinationNames(String internalId, ProcessToolContext ctx) {
     
      long start = System.currentTimeMillis();
        ProcessEngine engine = getProcessEngine(ctx);
        org.jbpm.api.ProcessInstance pi = engine.getExecutionService().findProcessInstanceById(internalId);
        final ExecutionImpl execution = (ExecutionImpl) pi.getProcessInstance();
        final List<String> transitionNames = new ArrayList<String>();
        engine.execute(new Command() {
            public Object execute(Environment env) {
                for (Transition transition : execution.getActivity().getOutgoingTransitions()) {
                    transitionNames.add(transition.getDestination().getName());
                }
                return null;
            }
        });

       
        long duration = System.currentTimeMillis() - start;
    log.severe("getOutgoingTransitionDestinationNames: " +  duration);
        return transitionNames;
    }

    private void fillProcessAssignmentData(final ProcessEngine processEngine, final ProcessInstance pi, ProcessToolContext ctx) {
        Set<String> assignees = new HashSet<String>();
        Set<String> queues = new HashSet<String>();
        TaskService taskService = processEngine.getTaskService();
        List<BpmTask> processTasks = findProcessTasks(pi, null, null, ctx);
        for (BpmTask t : processTasks) {
            if (t.getAssignee() != null) {
                assignees.add(t.getAssignee());
            } else { //some optimization could be possible
                for (Participation participation : taskService.getTaskParticipations(t.getInternalTaskId())) {
                    if ("candidate".equals(participation.getType())) {
                        queues.add(participation.getGroupId());
                    }
                }
            }
        }
        pi.setActiveTasks(processTasks.toArray(new BpmTask[processTasks.size()]));
        pi.setAssignees(assignees.toArray(new String[assignees.size()]));
        pi.setTaskQueues(queues.toArray(new String[queues.size()]));
    }

    private ProcessInstanceLog addActionLogEntry(ProcessStateAction action, BpmTask task, ProcessToolContext ctx) {
        ProcessStateConfiguration state = ctx.getProcessDefinitionDAO().getProcessStateConfiguration(task);

        ProcessInstanceLog log = new ProcessInstanceLog();
        if(AUTO_SKIP_ACTION_NAME.toLowerCase().equals(action.getBpmName().toLowerCase()))
          return log;
       
        log.setLogType(ProcessInstanceLog.LOG_TYPE_PERFORM_ACTION);
        log.setState(state);
        log.setEntryDate(Calendar.getInstance());
        log.setEventI18NKey("process.log.action-performed");
        log.setLogValue(action.getBpmName());
        log.setAdditionalInfo(nvl(action.getLabel(), action.getDescription(), action.getBpmName()));
        log.setUser(findOrCreateUser(user, ctx));
        log.setUserSubstitute(getSubstitutingUser(ctx));
        log.setExecutionId(task.getExecutionId());
        log.setOwnProcessInstance(task.getProcessInstance());
        task.getProcessInstance().getRootProcessInstance().addProcessLog(log);
        return log;
    }
    @Override
    public void adminCancelProcessInstance(ProcessInstance pi) {
        loger.severe("User: " + user.getLogin() + " attempting to cancel process: " + pi.getInternalId());
        long start = System.currentTimeMillis();
        ProcessToolContext ctx = ProcessToolContext.Util.getThreadProcessToolContext();
        pi = getProcessData(pi.getInternalId(), ctx);
        ProcessEngine processEngine = getProcessEngine(ctx);
        processEngine.getExecutionService().endProcessInstance(pi.getInternalId(), "admin-cancelled");
        fillProcessAssignmentData(processEngine, pi, ctx);
        pi.setRunning(false);
        pi.setState(null);
        ctx.getProcessInstanceDAO().saveProcessInstance(pi);
        long duration = System.currentTimeMillis() - start;
    log.severe("adminCancelProcessInstance: " +  duration);
        loger.severe("User: " + user.getLogin() + " has cancelled process: " + pi.getInternalId());

    }

        @Override
        public void adminReassignProcessTask(ProcessInstance pi, BpmTask bpmTask, String userLogin) {
            loger.severe("User: " + user.getLogin() + " attempting to reassign task " + bpmTask.getInternalTaskId() + " for process: " + pi.getInternalId() + " to user: " + userLogin);

            ProcessToolContext ctx = ProcessToolContext.Util.getThreadProcessToolContext();
            pi = getProcessData(pi.getInternalId(), ctx);
            ProcessEngine processEngine = getProcessEngine(ctx);
            TaskService ts = processEngine.getTaskService();
            Task task = ts.getTask(bpmTask.getInternalTaskId());
            if (nvl(userLogin,"").equals(nvl(task.getAssignee(),""))) {
                loger.severe("User: " + user.getLogin() + " has not reassigned task " + bpmTask.getInternalTaskId() + " for process: " + pi.getInternalId() + " as the user is the same: " + userLogin);
                return;
            }
            //this call should also take care of swimlanes
            ts.assignTask(bpmTask.getInternalTaskId(), userLogin);
            fillProcessAssignmentData(processEngine, pi, ctx);
            loger.info("Process.running:" + pi.getRunning());
            ctx.getProcessInstanceDAO().saveProcessInstance(pi);
            loger.severe("User: " + user.getLogin() + " has reassigned task " + bpmTask.getInternalTaskId() + " for process: " + pi.getInternalId() + " to user: " + userLogin);

        }

        @Override
        public void adminCompleteTask(ProcessInstance pi, BpmTask bpmTask, ProcessStateAction action) {
            loger.severe("User: " + user.getLogin() + " attempting to complete task " + bpmTask.getInternalTaskId() + " for process: " + pi.getInternalId() + " to outcome: " + action);
            performAction(action, bpmTask, ProcessToolContext.Util.getThreadProcessToolContext());
            loger.severe("User: " + user.getLogin() + " has completed task " + bpmTask.getInternalTaskId() + " for process: " + pi.getInternalId() + " to outcome: " + action);

        }

        public List<String> getAvailableLogins(final String filter) {
            Command<List<User>> cmd = new Command<List<User>>() {
                @Override
                public List<User> execute(Environment environment) throws Exception {
                    AbstractQuery q = new AbstractQuery() {
                        @Override
                        protected void applyPage(Query query) {
                            query.setFirstResult(0);
                            query.setFetchSize(20);
                        }

                        @Override
                        protected void applyParameters(Query query) {
                            query.setParameter("filter", "%" + filter + "%");
                        }

                        @Override
                        public String hql() {
                            StringBuilder hql = new StringBuilder();
                            hql.append("select user ");
                            hql.append("from ");
                            hql.append(UserImpl.class.getName());
                            hql.append(" as user ");
                            hql.append("where id like :filter ");

                            return hql.toString();

                        }
                    };
                    return (List<User>) q.execute(environment);
                }
            };
            List<User> users = getProcessEngine(ProcessToolContext.Util.getThreadProcessToolContext()).execute(cmd);
            List<String> res = new ArrayList<String>();
            for (User u : users) {
                res.add(u.getId());
            }
            java.util.Collections.sort(res);
            return res;

       

        @Override
        public List<GraphElement> getProcessHistory(final ProcessInstance pi) {
            ProcessEngine processEngine = getProcessEngine(ProcessToolContext.Util.getThreadProcessToolContext());
            HistoryService service = processEngine.getHistoryService();
            
            HistoryActivityInstanceQuery createHistoryActivityInstanceQuery = service.createHistoryActivityInstanceQuery();
            HistoryActivityInstanceQuery activityInstanceQuery = createHistoryActivityInstanceQuery.processInstanceId(pi.getInternalId());
            List<HistoryActivityInstance> list = activityInstanceQuery.list();
           
           
           
           
  
            Map<String,GraphElement> processGraphElements = parseProcessDefinition(pi);

           
           
            List<GraphElement> transitionaArcsList = new ArrayList<GraphElement>();
            Collection<GraphElement> pge = processGraphElements.values() ;
           
           
            for (GraphElement ge : pge) { 
                if( ge instanceof TransitionArc){
                  TransitionArc ta = (TransitionArc)ge;
                    transitionaArcsList.add(ta);
                 
              }
            }
           
       
           
            ArrayList<GraphElement> res = new ArrayList<GraphElement>();
            for (HistoryActivityInstance hpi : list) {
                loger.fine("Handling: " + hpi.getActivityName());
                if (hpi instanceof HistoryActivityInstanceImpl) {
                    HistoryActivityInstanceImpl activity = (HistoryActivityInstanceImpl) hpi;
                    String activityName = activity.getActivityName();
                    if (res.isEmpty()) { //initialize start node and its transition
                        GraphElement startNode = processGraphElements.get("__AWF__start_node");
                        if (startNode != null) {
                            res.add(startNode);
                        }
                        GraphElement firstTransition = processGraphElements.get("__AWF__start_transition_to_" + activityName);
                        if (firstTransition != null) {
                            res.add(firstTransition);
                        }
                    }
                  
                    StateNode sn = (StateNode) processGraphElements.get(activityName);
                   
                  
                   
                    ArrayList<StateNode> arrayList = new ArrayList<StateNode>();
                    Collection<GraphElement> values = processGraphElements.values();
                    for (GraphElement graphElement : values) {
            if(graphElement instanceof StateNode){
              arrayList.add((StateNode) graphElement);
            }
                     
                     
          }
                    if (sn == null) continue;
                    sn = sn.cloneNode();
                    sn.setUnfinished(activity.getEndTime() == null);
                    sn.setLabel(activityName + ": " + hpi.getDuration() + "ms");
                    res.add(sn);
                    //look for transition
                    TransitionArc ta = (TransitionArc) processGraphElements.get(activityName + "_" + activity.getTransitionName());
                    if (ta == null) { //look for default!
                        ta = (TransitionArc) processGraphElements.get("__AWF__default_transition_" + activityName);
                    }
                    if (ta == null) {
                        continue;
                    }
                   
           
                   
                 
                   
                    res.add(ta.cloneNode());
                } else {
                    loger.severe("Unsupported entry: " + hpi);
                }
            }
           
           addJoinAndForkElements(res,processGraphElements);
           
           
            HistoryProcessInstanceQuery historyProcessInstanceQuery = processEngine.getHistoryService()
                    .createHistoryProcessInstanceQuery().processInstanceId(pi.getInternalId());
            HistoryProcessInstance historyProcessInstance = historyProcessInstanceQuery.uniqueResult();
            if (historyProcessInstance != null && historyProcessInstance.getEndActivityName() != null) {
                StateNode sn = (StateNode) processGraphElements.get(historyProcessInstance.getEndActivityName());
                if (sn != null) {
                    StateNode e = sn.cloneNode();
                    e.setUnfinished(true);
                    res.add(e);
                }
            }
           
           
            return res;
        }
     
    
      
       
       

       

       
       
       

        private HashMap<String, GraphElement> parseProcessDefinition(ProcessInstance pi) {
            HashMap<String, GraphElement> res = new HashMap<String, GraphElement>();
            byte[] processDefinition = getProcessDefinition(pi);
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

            try {

                //Using factory get an instance of document builder
                DocumentBuilder db = dbf.newDocumentBuilder();
                //parse using builder to get DOM representation of the XML file
                Document dom = db.parse(new ByteArrayInputStream(processDefinition));
                Element documentElement = dom.getDocumentElement();
                String[] nodeTypes = new String[]{"start", "end", "java", "task", "decision","join","fork"};
                for (String nodeType : nodeTypes) {
                    NodeList nodes = documentElement.getElementsByTagName(nodeType);
                    for (int i = 0; i < nodes.getLength(); i++) {
                        Element node = (Element) nodes.item(i);
                        try {
                            StateNode sn = new StateNode();
                            String gval = node.getAttribute("g");
                            String[] vals = gval.split(",", 4);
                            int x = Integer.parseInt(vals[0]);
                            int y = Integer.parseInt(vals[1]);
                            int w = Integer.parseInt(vals[2]);
                            int h = Integer.parseInt(vals[3]);
                            sn.setX(x);
                            sn.setY(y);
                            sn.setWidth(w);
                            sn.setHeight(h);
                            sn.setNodeType(nodeType);
                            String name = node.getAttribute("name");
                            sn.setLabel(name);
                            res.put(name, sn);
                            if ("start".equals(nodeType)) {
                                res.put("__AWF__start_node", sn);
                            }
                            loger.fine("Found node" + name + ": " + x + "," + y + "," + w + "," + h);
                        } catch (Exception e) {
                            loger.log(Level.SEVERE, e.getMessage(), e);
                        }
                    }
                }
                    //once again - for transitions
                for (String nodeType : nodeTypes) {
                    NodeList nodes = documentElement.getElementsByTagName(nodeType);
                    for (int i = 0; i < nodes.getLength(); i++) {
                        Element node = (Element) nodes.item(i);
                        try {
                            String startNodeName = node.getAttribute("name");
                            StateNode startNode = (StateNode) res.get(startNodeName);
                            if (startNode == null) {
                                loger.severe("Start node " + startNodeName +
                                        " has not been localized, skipping transition drawing too.");
                                continue;
                            }
                            NodeList transitions = node.getElementsByTagName("transition");
                            for (int j=0; j < transitions.getLength(); j++) {
                                Element transitionEl = (Element) transitions.item(j);
                                String name = transitionEl.getAttribute("name");
                                String to = transitionEl.getAttribute("to") ;
                                StateNode endNode = (StateNode) res.get(to);
                                if (endNode == null) {
                                    loger.severe("End node " + to + " has not been localized for transition " + name +
                                            " of node " + startNodeName + ", skipping transition drawing.");
                                    continue;
                                }
                                String g = transitionEl.getAttribute("g");
                                if (g != null) {
                                    String[] dockersAndDistances = g.split(":");
                                    String[] dockers = new String[0];
                                    if (dockersAndDistances.length == 2) {
                                        dockers = dockersAndDistances[0].split(";");//what the other numbers mean - I have no idea...
                                    }
                                    //calculate line start node which is a center of the start node
                                    int startX = startNode.getX() + startNode.getWidth()/2;
                                    int startY = startNode.getY() + startNode.getHeight()/2;
                                    //and the same for end node
                                    int endX   = endNode.getX() + endNode.getWidth()/2;
                                    int endY   = endNode.getY() + endNode.getHeight()/2;

                                    TransitionArc arc = new TransitionArc();
                                    arc.setName(name);
                                    arc.addPoint(startX, startY);
                                    for (String docker : dockers) {
                                        String[] split = docker.split(",",2);
                                        arc.addPoint(Integer.parseInt(split[0]), Integer.parseInt(split[1]));
                                    }
                                    arc.addPoint(endX, endY);

                                    double a;//remember about vertical line
                                    double b;

                                    endX = arc.getPath().get(1).getX();
                                    endY = arc.getPath().get(1).getY();
                                    if (startX - endX == 0) { //whoa - vertical line - simple case, but requires special approach
                                        if (endY > startNode.getY()+startNode.getHeight()) { //below
                                            startY = startNode.getY()+startNode.getHeight();
                                        } else {
                                            startY = startNode.getY();
                                        }
                                    } else {
                                        a = ((double)(startY-endY))/((double)(startX - endX));
                                        b = (double)startY - (double)startX*a;
                                        for (int x = startX; x <= endX; x++) {
                                            int y = (int) Math.round(a*x+b);
                                            boolean inside = false;
                                            if (x >= startNode.getX() && x <= startNode.getX() + startNode.getWidth()) {
                                                if (y >= startNode.getY() && y <= startNode.getY() + startNode.getHeight()) {
                                                    inside = true;
                                                }
                                            }
                                            if (!inside) {
                                                startX = x;
                                                startY = y;
                                                break;
                                            }
                                        }
                                        for (int x = startX; x > endX; x--) {
                                            int y = (int) Math.round(a*x+b);
                                            boolean inside = false;
                                            if (x >= startNode.getX() && x <= startNode.getX() + startNode.getWidth()) {
                                                if (y >= startNode.getY() && y <= startNode.getY() + startNode.getHeight()) {
                                                    inside = true;
                                                }
                                            }
                                            if (!inside) {
                                                startX = x;
                                                startY = y;
                                                break;
                                            }
                                        }
                                    }
                                    arc.getPath().get(0).setX(startX);
                                    arc.getPath().get(0).setY(startY);

                                    endX = arc.getPath().get(arc.getPath().size()-1).getX();
                                    endY = arc.getPath().get(arc.getPath().size()-1).getY();
                                    startX = arc.getPath().get(arc.getPath().size()-2).getX();
                                    startY = arc.getPath().get(arc.getPath().size()-2).getY();
                                    if (startX - endX == 0) { //whoa - vertical line - simple case, but requires special approach
                                       if (startY > endNode.getY()+endNode.getHeight()) { //below
                                           endY = endNode.getY()+endNode.getHeight();
                                       } else {
                                           endY = endNode.getY();
                                       }
                                    } else {
                                        a = ((double)(startY-endY))/((double)(startX - endX));//remember about vertical line
                                        //startY = startX*a+b
                                        b = (double)startY - (double)startX*a;
                                        for (int x = endX; x <= startX; x++) {
                                            int y = (int) Math.round(a*x+b);
                                            boolean inside = false;
                                            if (x >= endNode.getX() && x <= endNode.getX() + endNode.getWidth()) {
                                                if (y >= endNode.getY() && y <= endNode.getY() + endNode.getHeight()) {
                                                    inside = true;
                                                }
                                            }
                                            if (!inside) {
                                                endX = x;
                                                endY = y;
                                                break;
                                            }
                                        }
                                        for (int x = endX; x > startX; x--) {
                                            int y = (int) Math.round(a*x+b);
                                            boolean inside = false;
                                            if (x >= endNode.getX() && x <= endNode.getX() + endNode.getWidth()) {
                                                if (y >= endNode.getY() && y <= endNode.getY() + endNode.getHeight()) {
                                                    inside = true;
                                                }
                                            }
                                            if (!inside) {
                                                endX = x;
                                                endY = y;
                                                break;
                                            }
                                        }
                                    }
                                    arc.getPath().get(arc.getPath().size()-1).setX(endX);
                                    arc.getPath().get(arc.getPath().size()-1).setY(endY);
                                    arc.setDestination(to);
                                    arc.setSource(startNodeName);

                                    res.put(startNodeName + "_" + name,arc);
                                    if ("start".equals(nodeType)) {
                                        res.put("__AWF__start_transition_to_" + to, arc);
                                    }
                                    if (transitions.getLength() == 1) {
                                        res.put("__AWF__default_transition_" + startNodeName, arc);
                                    }
                                } else {
                                    loger.severe("No 'g' attribute for transition "+ name +
                                                   " of node " + startNodeName + ", skipping transition drawing.");
                                }
                            }

                        } catch (Exception e) {
                            loger.log(Level.SEVERE, e.getMessage(), e);
                        }
                    }
                }


            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            return res;
        }
       
       
       
      private void addJoinAndForkElements(ArrayList<GraphElement> historyGraph,
          Map<String, GraphElement> originalGraphMap) {

        Map<String, StateNode> joinList = new HashMap<String, StateNode>();
        Map<String, StateNode> forkList = new HashMap<String, StateNode>();

        Map<GraphElement, List<TransitionArc>> joinWithTransitions = new HashMap<GraphElement, List<TransitionArc>>();
        Map<GraphElement, List<TransitionArc>> forkWithTransitions = new HashMap<GraphElement, List<TransitionArc>>();

        List<TransitionArc> transitionArcList = new ArrayList<TransitionArc>();

        Collection<GraphElement> originalGraph = originalGraphMap.values();

        for (GraphElement originalGraphElement : originalGraph) {

          fillListWithAllPosibleTransitionArc(originalGraphElement,
              transitionArcList);
          fillListsWithAllPosibleJoinAndForkNodes(originalGraphElement,
              joinList, forkList);

        }

        if (joinList.size() > 0 || forkList.size() > 0) {

          for (TransitionArc transitionArc : transitionArcList) {
            relateNodesWithTransitionArcs(forkList, transitionArc,
                forkWithTransitions);
            relateNodesWithTransitionArcs(joinList, transitionArc,
                joinWithTransitions);
          }

          Set<GraphElement> forks = forkWithTransitions.keySet();
          ArrayList<String> tasksNamesFromHistoryAsArray = getTasksNamesFromHistoryAsArray(historyGraph);

          for (GraphElement fork : forks) {
            List<TransitionArc> forkTransitions = forkWithTransitions
                .get(fork);
            if (isForkOutgoingsExistsInHistoryGraph(forkTransitions, fork,
                tasksNamesFromHistoryAsArray)) {
              historyGraph.addAll(forkTransitions);
              historyGraph.add(fork);
            }

          }

          Set<GraphElement> joins = joinWithTransitions.keySet();
          for (GraphElement join : joins) {
            List<TransitionArc> list = joinWithTransitions.get(join);
            if (isJoinOutgoingWasMissingInHistoryGraph(list,
                tasksNamesFromHistoryAsArray, historyGraph)) {
              historyGraph.add(join);
            }

          }
        }

      }

      private void fillListWithAllPosibleTransitionArc(
          GraphElement originalGraphElement,
          List<TransitionArc> transitionArcList) {

        if (originalGraphElement instanceof TransitionArc) {
          TransitionArc transitionArc = (TransitionArc) originalGraphElement;
          transitionArcList.add(transitionArc);
        }

      }

      private void fillListsWithAllPosibleJoinAndForkNodes(
          GraphElement originalGraphElement, Map<String, StateNode> joinList,
          Map<String, StateNode> forkList) {

        if (originalGraphElement instanceof StateNode) {

          updateNodeList(joinList, JOIN_NODE_NAME, originalGraphElement);

          updateNodeList(forkList, FORK_NODE_NAME, originalGraphElement);

        }

      }

      private void updateNodeList(Map<String, StateNode> nodeList,
          String nodeType, GraphElement originalGraphElement) {

        StateNode stateNode = (StateNode) originalGraphElement;

        if (stateNode.getNodeType() != null
            && (stateNode.getNodeType().equals(nodeType))) {

          nodeList.put(stateNode.getLabel(), stateNode);
        }

      }

      private void relateNodesWithTransitionArcs(
          Map<String, StateNode> joinForkList, TransitionArc transitionArc,
          Map<GraphElement, List<TransitionArc>> joinOrForkWithTransitions) {
        if (joinForkList.containsKey(transitionArc.getSource())) {
          StateNode stateNode = joinForkList.get(transitionArc.getSource());
          List<TransitionArc> listOfTransition = null;

          if (joinOrForkWithTransitions.containsKey(stateNode)) {

            listOfTransition = joinOrForkWithTransitions.get(stateNode);
          } else {
            listOfTransition = new ArrayList<TransitionArc>();
          }

          listOfTransition.add(transitionArc);
          joinOrForkWithTransitions.put(stateNode, listOfTransition);

        }

      }

      private ArrayList<String> getTasksNamesFromHistoryAsArray(
          ArrayList<GraphElement> historyGraph) {

        ArrayList<String> newHistoryElement = new ArrayList<String>();
        for (GraphElement historyElement : historyGraph) {
          if (historyElement instanceof StateNode) {
            StateNode historyNode = (StateNode) historyElement;
            String histloryNodeLabel = historyNode.getLabel();
            String[] split = histloryNodeLabel.split(":");

            String taskNameFromHistory = split[0];
            newHistoryElement.add(taskNameFromHistory);
          }

        }

        return newHistoryElement;
      }

      private boolean isForkOutgoingsExistsInHistoryGraph(
          List<TransitionArc> list, GraphElement fork,
          ArrayList<String> tasksNamesFromHistoryAsArray) {

        int apperenceCounter = list.size();
        for (TransitionArc transitionArc : list) {
          if (tasksNamesFromHistoryAsArray.contains(transitionArc
              .getDestination())) {
            apperenceCounter--;
          }

        }
        if (apperenceCounter == 0) {
          return true;

        }

        return false;

      }

      private boolean isJoinOutgoingWasMissingInHistoryGraph(
          List<TransitionArc> list,
          ArrayList<String> tasksNamesFromHistoryAsArray,
          ArrayList<GraphElement> historyGraph) {
        boolean addedTransition = false;

        for (TransitionArc transitionArc : list) {
          if (tasksNamesFromHistoryAsArray.contains(transitionArc
              .getDestination())) {
            historyGraph.add(transitionArc);
            addedTransition = true;
          }
        }

        if (addedTransition == true) {
          return true;

        }

        return false;

      }
       

        @Override
        public byte[] getProcessLatestDefinition(String definitionKey, String processName) {
            String resourceName = processName + ".jpdl.xml";
           
            long start = System.currentTimeMillis();
             byte[] fetchLatestProcessResource = fetchLatestProcessResource(definitionKey, resourceName);
            
             long duration = System.currentTimeMillis() - start;
       log.severe("getProcessLatestDefinition: " +  duration);
             return fetchLatestProcessResource;
        }

        @Override
        public byte[] getProcessMapImage(ProcessInstance pi) {
         
           long start = System.currentTimeMillis();
            String resourceName = pi.getDefinition().getProcessName() + ".png";
             byte[] processResource = fetchProcessResource(pi, resourceName);
            
             long duration = System.currentTimeMillis() - start;
       log.severe("getProcessMapImage: " +  duration);
            
             return processResource;
        }

        @Override
        public byte[] getProcessDefinition(ProcessInstance pi) {
         
           long start = System.currentTimeMillis();
          
            String resourceName = pi.getDefinition().getProcessName() + ".jpdl.xml";
             byte[] processResource = fetchProcessResource(pi, resourceName);
            
             long duration = System.currentTimeMillis() - start;
       log.severe("getProcessDefinition: " +  duration);
            
             return processResource;
        }

        private byte[] fetchLatestProcessResource(String definitionKey, String resourceName) {
            RepositoryService service = getProcessEngine(ProcessToolContext.Util.getThreadProcessToolContext())
                    .getRepositoryService();
            List<ProcessDefinition> latestList = service.createProcessDefinitionQuery()
                    .processDefinitionKey(definitionKey).orderDesc("deployment.dbid").page(0, 1).list();
            if (!latestList.isEmpty()) {
                String oldDeploymentId = latestList.get(0).getDeploymentId();
                return getDeploymentResource(resourceName, oldDeploymentId);
            }
            return null;
        }
        private byte[] fetchProcessResource(ProcessInstance pi, String resourceName) {
            ProcessEngine processEngine = getProcessEngine(ProcessToolContext.Util.getThreadProcessToolContext());
            RepositoryService service = processEngine.getRepositoryService();

            ExecutionService executionService = processEngine.getExecutionService();
            org.jbpm.api.ProcessInstance processInstanceById = executionService.findProcessInstanceById(pi.getInternalId());
            String processDefinitionId;
            if (processInstanceById == null) { //look in history service
                HistoryProcessInstanceQuery historyProcessInstanceQuery = processEngine.getHistoryService()
                        .createHistoryProcessInstanceQuery().processInstanceId(pi.getInternalId());
                HistoryProcessInstance historyProcessInstance = historyProcessInstanceQuery.uniqueResult();
                processDefinitionId = historyProcessInstance.getProcessDefinitionId();
            } else {
                processDefinitionId = processInstanceById.getProcessDefinitionId();
            }
            List<ProcessDefinition> latestList = service.createProcessDefinitionQuery()
                    .processDefinitionId(processDefinitionId).orderDesc("deployment.dbid").page(0, 1).list();
            if (!latestList.isEmpty()) {
                String oldDeploymentId = latestList.get(0).getDeploymentId();
                return getDeploymentResource(resourceName, oldDeploymentId);
            }
            return null;
        }

        private byte[] getDeploymentResource(String resourceName, String oldDeploymentId) {
            RepositoryService service = getProcessEngine(ProcessToolContext.Util.getThreadProcessToolContext()).getRepositoryService();;
            try {
                InputStream oldStream = service.getResourceAsStream(oldDeploymentId, resourceName);
                try {
                    if (oldStream != null) {
                        ByteArrayOutputStream bos2 = new ByteArrayOutputStream();
                        int c;
                        while ((c = oldStream.read()) >= 0) {
                            bos2.write(c);
                        }
                        return bos2.toByteArray();
                    }
                } finally {
                    if (oldStream != null) {
                        oldStream.close();
                    }
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            return null;
        }

        public String deployProcessDefinition(String processName, InputStream definitionStream, InputStream processMapImageStream) {
            RepositoryService service = getProcessEngine(ProcessToolContext.Util.getThreadProcessToolContext())
                    .getRepositoryService();
            NewDeployment deployment = service.createDeployment();
            deployment.addResourceFromInputStream(processName + ".jpdl.xml", definitionStream);
            if (processMapImageStream != null)
                deployment.addResourceFromInputStream(processName + ".png", processMapImageStream);
            return deployment.deploy();
        }

    public String getProcessState(ProcessInstance pi, ProcessToolContext ctx) {
        List<BpmTask> tasks = findProcessTasks(pi, ctx);
        for (BpmTask task : tasks) {
            return task.getTaskName();
        }
        return null;
    }
}
TOP

Related Classes of pl.net.bluesoft.rnd.pt.ext.jbpm.ProcessToolJbpmSession

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.