1   /*
2    * Copyright 2003 - 2013 The eFaps Team
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   *
16   * Revision:        $Rev: 9284 $
17   * Last Changed:    $Date: 2013-04-26 10:40:07 -0500 (Fri, 26 Apr 2013) $
18   * Last Changed By: $Author: jan@moxter.net $
19   */
20  
21  package org.efaps.bpm;
22  
23  import java.io.InputStream;
24  import java.lang.reflect.InvocationTargetException;
25  import java.lang.reflect.Method;
26  import java.util.ArrayList;
27  import java.util.Collection;
28  import java.util.Collections;
29  import java.util.HashMap;
30  import java.util.List;
31  import java.util.Map;
32  import java.util.UUID;
33  import java.util.concurrent.ExecutorService;
34  import java.util.concurrent.Executors;
35  
36  import javax.naming.InitialContext;
37  import javax.naming.NamingException;
38  import javax.persistence.EntityManagerFactory;
39  import javax.persistence.Persistence;
40  import javax.transaction.UserTransaction;
41  
42  import org.apache.commons.lang3.concurrent.BasicThreadFactory;
43  import org.drools.persistence.jta.JtaTransactionManager;
44  import org.efaps.admin.EFapsSystemConfiguration;
45  import org.efaps.admin.KernelSettings;
46  import org.efaps.admin.common.SystemConfiguration;
47  import org.efaps.admin.dbproperty.DBProperties;
48  import org.efaps.admin.event.Parameter;
49  import org.efaps.admin.event.Parameter.ParameterValues;
50  import org.efaps.admin.event.Return;
51  import org.efaps.admin.event.Return.ReturnValues;
52  import org.efaps.admin.program.esjp.EFapsClassLoader;
53  import org.efaps.admin.user.AbstractUserObject;
54  import org.efaps.admin.user.Role;
55  import org.efaps.bpm.compiler.KnowledgeBuilderFactoryServiceImpl;
56  import org.efaps.bpm.identity.EntityMapper;
57  import org.efaps.bpm.identity.UserGroupCallbackImpl;
58  import org.efaps.bpm.listener.AsyncCalls;
59  import org.efaps.bpm.listener.IAsyncListener;
60  import org.efaps.bpm.listener.WorkingMemoryLogListener;
61  import org.efaps.bpm.process.ProcessAdmin;
62  import org.efaps.bpm.runtime.ManagerFactoryImpl;
63  import org.efaps.bpm.runtime.RegisterableItemsFactoryImpl;
64  import org.efaps.bpm.task.TaskAdminstration;
65  import org.efaps.bpm.transaction.ConnectionProvider;
66  import org.efaps.bpm.transaction.TransactionHelper;
67  import org.efaps.bpm.workitem.ManualTaskItemHandler;
68  import org.efaps.ci.CIAdminProgram;
69  import org.efaps.db.Checkout;
70  import org.efaps.db.Context;
71  import org.efaps.db.InstanceQuery;
72  import org.efaps.db.QueryBuilder;
73  import org.efaps.util.EFapsException;
74  import org.efaps.util.cache.CacheReloadException;
75  import org.hibernate.cfg.AvailableSettings;
76  import org.jbpm.process.audit.JPAAuditLogService;
77  import org.jbpm.runtime.manager.impl.PerProcessInstanceRuntimeManager;
78  import org.jbpm.runtime.manager.impl.RuntimeEnvironmentBuilder;
79  import org.jbpm.services.task.impl.model.I18NTextImpl;
80  import org.jbpm.services.task.utils.ContentMarshallerHelper;
81  import org.jbpm.workflow.instance.WorkflowProcessInstance;
82  import org.kie.api.io.ResourceType;
83  import org.kie.api.runtime.KieSession;
84  import org.kie.api.runtime.manager.RuntimeEngine;
85  import org.kie.api.runtime.manager.RuntimeManager;
86  import org.kie.api.runtime.process.NodeInstance;
87  import org.kie.api.runtime.process.ProcessInstance;
88  import org.kie.api.task.TaskService;
89  import org.kie.api.task.model.Content;
90  import org.kie.api.task.model.I18NText;
91  import org.kie.api.task.model.OrganizationalEntity;
92  import org.kie.api.task.model.Status;
93  import org.kie.api.task.model.Task;
94  import org.kie.api.task.model.TaskSummary;
95  import org.kie.internal.builder.KnowledgeBuilderFactoryService;
96  import org.kie.internal.io.ResourceFactory;
97  import org.kie.internal.runtime.manager.Mapper;
98  import org.kie.internal.runtime.manager.RuntimeEnvironment;
99  import org.kie.internal.runtime.manager.context.CorrelationKeyContext;
100 import org.kie.internal.runtime.manager.context.EmptyContext;
101 import org.kie.internal.runtime.manager.context.ProcessInstanceIdContext;
102 import org.kie.internal.task.api.InternalTaskService;
103 import org.kie.internal.task.api.model.InternalTask;
104 import org.kie.internal.utils.ServiceRegistryImpl;
105 import org.slf4j.Logger;
106 import org.slf4j.LoggerFactory;
107 /**
108  * TODO comment!
109  *
110  * @author The eFaps Team
111  * @version $Id: BPM.java 9284 2013-04-26 15:40:07Z jan@moxter.net $
112  */
113 public final class BPM
114 {
115     /**
116      * Parameter key to be used to pass to the process.
117      */
118     public static final String OUTPARAMETER4TASKDECISION = "eFapsDecision";
119 
120     /**
121      * Parameter key to be used to pass delegates to an Human Task.
122      */
123     public static final String INPUTPARAMETER4DELEGATE = "DelegateIds";
124 
125     /**
126      * Logging instance used in this class.
127      */
128     private static final Logger LOG = LoggerFactory.getLogger(BPM.class);
129 
130     /**
131      * SingletonRuntimeManager.
132      */
133     private static RuntimeManager SMANAGER;
134 
135     /**
136      * PerProcessInstanceRuntimeManager.
137      */
138     private static RuntimeManager PMANAGER;
139 
140     /**
141      * Create Singelton.
142      */
143     private BPM()
144     {
145     }
146 
147     /**
148      * Initialize BPM.
149      *
150      * @throws EFapsException on error
151      */
152     public static void initialize()
153         throws EFapsException
154     {
155         final SystemConfiguration config = EFapsSystemConfiguration.get();
156         final boolean active = config != null
157                         ? config.getAttributeValueAsBoolean(KernelSettings.ACTIVATE_BPM) : false;
158         if (active) {
159 
160             if (BPM.PMANAGER != null) {
161                 BPM.PMANAGER.close();
162                 BPM.PMANAGER = null;
163             }
164             if (BPM.SMANAGER != null) {
165                 BPM.SMANAGER.close();
166                 BPM.SMANAGER = null;
167             }
168 
169             UserTransaction userTrans = null;
170             InitialContext context = null;
171             try {
172                 context = new InitialContext();
173                 userTrans = TransactionHelper.findUserTransaction();
174                 Object object = null;
175                 try {
176                     object = context.lookup(JtaTransactionManager.DEFAULT_USER_TRANSACTION_NAME);
177                 } catch (final NamingException ex) {
178                     BPM.LOG.info("Checked for JtaTransactionManager");
179                 }
180                 if (object == null) {
181                     context.bind(JtaTransactionManager.DEFAULT_USER_TRANSACTION_NAME, userTrans);
182                     context.bind(JtaTransactionManager.FALLBACK_TRANSACTION_MANAGER_NAMES[0],
183                                     TransactionHelper.findTransactionManager());
184                 }
185             } catch (final NamingException ex) {
186                 BPM.LOG.error("Could not initialise JNDI InitialContext", ex);
187             }
188 
189             // register our own KnowledgeBuilderFactoryService
190             ServiceRegistryImpl.getInstance().addDefault(KnowledgeBuilderFactoryService.class,
191                             KnowledgeBuilderFactoryServiceImpl.class.getName());
192 
193             final RegisterableItemsFactoryImpl itemsFactory = new RegisterableItemsFactoryImpl();
194             itemsFactory.addWorkItemHandler("Manual Task", ManualTaskItemHandler.class);
195             itemsFactory.addProcessListener(WorkingMemoryLogListener.class);
196 
197             final Map<String, String> properties = new HashMap<String, String>();
198             properties.put(AvailableSettings.DIALECT, Context.getDbType().getHibernateDialect());
199             properties.put(AvailableSettings.SHOW_SQL, String.valueOf(BPM.LOG.isDebugEnabled()));
200             properties.put(AvailableSettings.FORMAT_SQL, "true");
201             properties.put(AvailableSettings.RELEASE_CONNECTIONS, "after_transaction");
202             properties.put(AvailableSettings.CONNECTION_PROVIDER, ConnectionProvider.class.getName());
203             properties.put(org.hibernate.jpa.AvailableSettings.NAMING_STRATEGY, NamingStrategy.class.getName());
204 
205             final EntityManagerFactory emf = Persistence
206                             .createEntityManagerFactory("org.jbpm.persistence.jpa", properties);
207 
208             final RuntimeEnvironmentBuilder builder = RuntimeEnvironmentBuilder.getDefault()
209                             .classLoader(EFapsClassLoader.getInstance())
210                             .userGroupCallback(new UserGroupCallbackImpl())
211                             .entityManagerFactory(emf)
212                             .registerableItemsFactory(itemsFactory)
213                             .persistence(true)
214                             .addEnvironmentEntry("TRANSACTION_LOCK_ENABLED", "false");
215 
216             BPM.add2EnvironmentBuilder(builder);
217 
218             final RuntimeEnvironment environment = builder.get();
219             final ManagerFactoryImpl factory = new ManagerFactoryImpl();
220 
221             BPM.PMANAGER = factory.newPerProcessInstanceRuntimeManager(environment);
222             BPM.SMANAGER = factory.newSingletonRuntimeManager(environment);
223         }
224     }
225 
226     /**
227      * @param _envBuilder RuntimeEnvironmentBuilder
228      * @throws EFapsException on error
229      */
230     private static void add2EnvironmentBuilder(final RuntimeEnvironmentBuilder _envBuilder)
231         throws EFapsException
232     {
233         final QueryBuilder queryBldr = new QueryBuilder(CIAdminProgram.BPM);
234         final InstanceQuery query = queryBldr.getQuery();
235         query.executeWithoutAccessCheck();
236         while (query.next()) {
237             final Checkout checkout = new Checkout(query.getCurrentValue());
238             final InputStream in = checkout.execute();
239             _envBuilder.addAsset(ResourceFactory.newInputStreamResource(in), ResourceType.BPMN2);
240         }
241     }
242 
243     /**
244      * @param _processId    id of the process to start
245      * @param _params       parameter map for the task
246      * @return the <code>ProcessInstance</code> that represents the instance of the process that was started
247      */
248     public static ProcessInstance startProcess(final String _processId,
249                                                final Map<String, Object> _params)
250     {
251         final RuntimeEngine runtimeEngine = BPM.PMANAGER.getRuntimeEngine(CorrelationKeyContext.get());
252         final KieSession ksession = runtimeEngine.getKieSession();
253         return ksession.startProcess(_processId, _params);
254     }
255 
256     /**
257      * Returns all node instances that are currently active within this container.
258      * @param _processInstanceId if of a process Instance
259      * @return the list of node instances currently active, empty list if none found
260      */
261     public static Collection<NodeInstance> getActiveNodes4ProcessId(final long _processInstanceId)
262     {
263         ProcessInstance processInstance = null;
264         if (BPM.processIsActiv(_processInstanceId)) {
265             final RuntimeEngine runtimeEngine = BPM.PMANAGER.getRuntimeEngine(ProcessInstanceIdContext
266                             .get(_processInstanceId));
267             final KieSession ksession = runtimeEngine.getKieSession();
268             processInstance = ksession.getProcessInstance(_processInstanceId);
269         }
270         return processInstance == null ? Collections.<NodeInstance>emptyList()
271                         : ((WorkflowProcessInstance) processInstance).getNodeInstances();
272     }
273 
274     /**
275      * Check for the PerProcessInstanceRuntimeManager if the process for the
276      * given processInstanceId is still active.
277      *
278      * @param _processInstanceId processInstanceId to be checked if still activ
279      * @return true if activ, else fasle
280      */
281     public static boolean processIsActiv(final long _processInstanceId)
282     {
283         final ProcessInstanceIdContext context = ProcessInstanceIdContext.get(_processInstanceId);
284         final Mapper mapper = ((PerProcessInstanceRuntimeManager) BPM.PMANAGER).getMapper();
285         return mapper.findMapping(context, null) != null;
286     }
287 
288     /**
289      * @param _processInstanceId id of the processinstanc to be aborted
290      */
291     public static void abortProcessInstance(final long _processInstanceId)
292     {
293         final RuntimeEngine runtimeEngine = BPM.PMANAGER.getRuntimeEngine(ProcessInstanceIdContext
294                         .get(_processInstanceId));
295         runtimeEngine.getKieSession().abortProcessInstance(_processInstanceId);
296     }
297 
298     /**
299      * When the task has a single potential owner, it transitions into the
300      * Reserved state, indicating that it is assigned to a single actual owner.
301      * Otherwise (i.e., when it has multiple potential owners or is assigned to
302      * a work queue), it transitions into the Ready state, indicating that it
303      * can be claimed by one of its potential owners. Once a potential owner
304      * claims the task, it transitions into the Reserved state, making that
305      * potential owner the actual owner.
306      *
307      * @param _taskSummary task to be claimed
308      * @throws EFapsException on error
309      */
310     public static void claimTask(final TaskSummary _taskSummary)
311         throws EFapsException
312     {
313         final RuntimeEngine runtimeEngine = BPM.PMANAGER.getRuntimeEngine(ProcessInstanceIdContext.get(_taskSummary
314                         .getProcessInstanceId()));
315         final TaskService taskService = runtimeEngine.getTaskService();
316         // check if must be claimed still
317         if (Status.Ready.equals(_taskSummary.getStatus())) {
318             taskService.claim(_taskSummary.getId(),
319                             EntityMapper.getUserId(Context.getThreadContext().getPerson().getUUID()));
320         }
321     }
322 
323     /**
324      * Task’s potential owners, actual owner or business administrator can
325      * forward an active task to another person or a set of people, replacing
326      * himself by those people in the list of potential owners. Potential owners
327      * can only forward tasks that are in the Ready state. Forwarding is
328      * possible if the task has a set of individually assigned potential owners,
329      * not if its potential owners are assigned using one or many groups. If the
330      * task is in the Reserved or InProgress state then the task is implicitly
331      * released first, that is, the task is transitioned into the Ready state.
332      * Business data associated with the task is kept. The user performing the
333      * forward is removed from the set of potential owners of the task, and the
334      * forwardee is added to the set of potential owners.
335      *
336      * @param _taskSummary task to be claimed
337      * @param _targetEntityId target entity
338      * @throws EFapsException on error
339      */
340     public static void forwardTask(final TaskSummary _taskSummary,
341                                    final String _targetEntityId)
342         throws EFapsException
343     {
344         final RuntimeEngine runtimeEngine = BPM.PMANAGER.getRuntimeEngine(ProcessInstanceIdContext.get(_taskSummary
345                         .getProcessInstanceId()));
346         final TaskService taskService = runtimeEngine.getTaskService();
347         taskService.forward(_taskSummary.getId(),
348                         EntityMapper.getUserId(Context.getThreadContext().getPerson().getUUID()),
349                         EntityMapper.getEntityId(_targetEntityId));
350     }
351 
352     /**
353      * Task’s potential owners, actual owner or business administrator can
354      * delegate a task to another user, making that user the actual owner of the
355      * task, and also adding her to the list of potential owners in case she is
356      * not, yet. A task can be delegated when it is in an active state (Ready,
357      * Reserved, InProgress), and transitions the task into the Reserved state.
358      * Business data associated with the task is kept.
359      *
360      * @param _taskSummary  TaskSummary
361      * @param _targetEntityId   target entity
362      * @throws EFapsException on error
363      */
364     public static void delegateTask(final TaskSummary _taskSummary,
365                                     final String _targetEntityId)
366         throws EFapsException
367     {
368         final RuntimeEngine runtimeEngine = BPM.PMANAGER.getRuntimeEngine(ProcessInstanceIdContext.get(_taskSummary
369                         .getProcessInstanceId()));
370         final TaskService taskService = runtimeEngine.getTaskService();
371         taskService.delegate(_taskSummary.getId(),
372                         EntityMapper.getUserId(Context.getThreadContext().getPerson().getUUID()),
373                         EntityMapper.getEntityId(_targetEntityId));
374     }
375 
376 
377     /**
378      * @param _taskSummary taskSummary the Delegate Roles are wanted for.
379      * @return List of Roles
380      * @throws CacheReloadException on error
381      */
382     public static List<Role> getDelegates4Task(final TaskSummary _taskSummary)
383         throws CacheReloadException
384     {
385         final List<Role> ret = new ArrayList<Role>();
386         final Object values = BPM.getTaskData(_taskSummary);
387         if (values instanceof Map) {
388             final String delegatesStr = (String) ((Map<?, ?>) values).get(BPM.INPUTPARAMETER4DELEGATE);
389             if (delegatesStr != null && !delegatesStr.isEmpty()) {
390                 final String[] delegates = delegatesStr.split(";");
391                 for (final String delegate : delegates) {
392                     final Role role = Role.get(UUID.fromString(delegate));
393                     if (role != null) {
394                         ret.add(role);
395                     }
396                 }
397             }
398         }
399         return ret;
400     }
401 
402     /**
403      * @param _taskSummary task to be delgate
404      * @param _targetUserId userid of the user the task will be delegated to
405      * @throws EFapsException on error
406      */
407     public static void delegateTask4Role(final TaskSummary _taskSummary,
408                                          final String _targetUserId)
409         throws EFapsException
410     {
411         final RuntimeEngine runtimeEngine = BPM.PMANAGER.getRuntimeEngine(CorrelationKeyContext.get());
412         final TaskService taskService = runtimeEngine.getTaskService();
413        // runtimeEngine.getKieSession().execute(new GenericCommand(){})
414         // check if must be claimed still
415         if (Status.Ready.equals(_taskSummary.getStatus())) {
416             boolean add = true;
417             final Task task = taskService.getTaskById(_taskSummary.getId());
418             final List<OrganizationalEntity> owners = task.getPeopleAssignments().getPotentialOwners();
419             for (final OrganizationalEntity org : owners) {
420                 if (_targetUserId.equals(org.getId())) {
421                     add = false;
422                 }
423             }
424             if (add) {
425                 final boolean isRole = Role.get(UUID.fromString(_targetUserId)) != null;
426                 if (isRole) {
427 //  final List<OperationCommand> commands = taskService.getCommandsForOperation(Operation.Delegate);
428 //                    for (final OperationCommand cmd : commands) {
429 //                        cmd.setExec(Operation.Delegate);
430 //                    }
431                 }
432 
433                 taskService.delegate(_taskSummary.getId(),
434                                 EntityMapper.getUserId(Context.getThreadContext().getPerson().getUUID()),
435                                 _targetUserId);
436 
437                 final List<I18NText> descr = task.getDescriptions();
438                 final String txt = DBProperties.getFormatedDBProperty(
439                                 "org.efaps.bpm.BPM.delegateText",
440                                 new Object[] { Context.getThreadContext().getPerson().getName(),
441                                           AbstractUserObject.getUserObject(UUID.fromString(_targetUserId)).getName() });
442                 if (descr.isEmpty()) {
443                     final I18NTextImpl i18n = new I18NTextImpl();
444                     i18n.setText(txt);
445                     i18n.setLanguage("en-UK");
446                     descr.add(i18n);
447                 } else {
448                     final String oldTxt = descr.get(0).getText();
449                     if (!oldTxt.contains(txt)) {
450                         ((I18NTextImpl) descr.get(0)).setText(descr.get(0).getText() + " - " + txt);
451                     }
452                 }
453 
454                 if (isRole) {
455 //                    final List<OperationCommand> commands = taskService.getCommandsForOperation(Operation.Delegate);
456 //                    for (final OperationCommand cmd : commands) {
457 //                        cmd.setExec(Operation.Claim);
458 //                    }
459                 }
460             }
461         }
462     }
463 
464     /**
465      * The current actual owner of a human task may release a task to again make
466      * it available for all potential owners. A task can be released from active
467      * states that have an actual owner (Reserved, InProgress), transitioning it
468      * into the Ready state. Business data associated with the task
469      * (intermediate result data, ad-hoc attachments and comments) is kept. A
470      * task that is currently InProgress can be stopped by the actual owner,
471      * transitioning it into state Reserved. Business data associated with the
472      * task as well as its actual owner is kept.
473      *
474      * @param _taskSummary task to be claimed
475      * @throws EFapsException on error
476      */
477     public static void releaseTask(final TaskSummary _taskSummary)
478         throws EFapsException
479     {
480         final RuntimeEngine runtimeEngine = BPM.PMANAGER.getRuntimeEngine(ProcessInstanceIdContext.get(_taskSummary
481                         .getProcessInstanceId()));
482         final TaskService taskService = runtimeEngine.getTaskService();
483         // check if must be claimed still
484         if (Status.Reserved.equals(_taskSummary.getStatus())) {
485             taskService.release(_taskSummary.getId(),
486                             EntityMapper.getUserId(Context.getThreadContext().getPerson().getUUID()));
487         }
488     }
489 
490     /**
491      * Stop a task that is in process.
492      *
493      * @param _taskSummary task to be claimed
494      * @throws EFapsException on error
495      */
496     public static void stopTask(final TaskSummary _taskSummary)
497         throws EFapsException
498     {
499         final RuntimeEngine runtimeEngine = BPM.PMANAGER.getRuntimeEngine(ProcessInstanceIdContext.get(_taskSummary
500                         .getProcessInstanceId()));
501         final TaskService taskService = runtimeEngine.getTaskService();
502         taskService.stop(_taskSummary.getId(),
503                         EntityMapper.getUserId(Context.getThreadContext().getPerson().getUUID()));
504     }
505 
506     /**
507      * Stop a task that is in process.
508      *
509      * @param _taskSummary task to be claimed
510      * @throws EFapsException on error
511      */
512     public static void exitTask(final TaskSummary _taskSummary)
513         throws EFapsException
514     {
515         final RuntimeEngine runtimeEngine = BPM.PMANAGER.getRuntimeEngine(ProcessInstanceIdContext.get(_taskSummary
516                         .getProcessInstanceId()));
517         final TaskService taskService = runtimeEngine.getTaskService();
518         taskService.exit(_taskSummary.getId(),
519                         EntityMapper.getUserId(Context.getThreadContext().getPerson().getUUID()));
520     }
521 
522     /**
523      * @param _taskSummary TaskSummary
524      * @param _decision one of true, false, null
525      * @param _values mapping of additional values
526      * @throws EFapsException on error
527      */
528     public static void executeTask(final TaskSummary _taskSummary,
529                                    final Boolean _decision,
530                                    final Map<String, Object> _values)
531         throws EFapsException
532     {
533         final RuntimeEngine runtimeEngine = BPM.PMANAGER.getRuntimeEngine(ProcessInstanceIdContext.get(_taskSummary
534                         .getProcessInstanceId()));
535         final TaskService taskService = runtimeEngine.getTaskService();
536 
537         // check if must be claimed still
538         if (Status.Ready.equals(_taskSummary.getStatus())) {
539             taskService.claim(_taskSummary.getId(),
540                             EntityMapper.getUserId(Context.getThreadContext().getPerson().getUUID()));
541         }
542         if (Status.InProgress.equals(_taskSummary.getStatus())) {
543             taskService.resume(_taskSummary.getId(),
544                             EntityMapper.getUserId(Context.getThreadContext().getPerson().getUUID()));
545         } else {
546             taskService.start(_taskSummary.getId(),
547                             EntityMapper.getUserId(Context.getThreadContext().getPerson().getUUID()));
548         }
549 
550         final Parameter parameter = new Parameter();
551         parameter.put(ParameterValues.BPM_TASK, _taskSummary);
552         parameter.put(ParameterValues.BPM_VALUES, _values);
553         parameter.put(ParameterValues.BPM_DECISION, _decision);
554         final Map<String, Object> results = new HashMap<String, Object>();
555         if (_values != null) {
556             results.putAll(_values);
557         }
558         // exec esjp
559         try {
560             final Class<?> transformer = Class.forName("org.efaps.esjp.bpm.TaskTransformer", true,
561                             EFapsClassLoader.getInstance());
562             final Method method = transformer.getMethod("execute", new Class[] { Parameter.class });
563             final Return ret = (Return) method.invoke(transformer.newInstance(), parameter);
564             if (ret != null) {
565                 results.put(BPM.OUTPARAMETER4TASKDECISION, ret.get(ReturnValues.VALUES));
566             }
567         } catch (final ClassNotFoundException e) {
568             BPM.LOG.error("Class could not be found.", e);
569         } catch (final InstantiationException e) {
570             BPM.LOG.error("Class could not be instantiation.", e);
571         } catch (final IllegalAccessException e) {
572             BPM.LOG.error("Class could not be accessed.", e);
573         } catch (final IllegalArgumentException e) {
574             BPM.LOG.error("Illegal Argument.", e);
575         } catch (final InvocationTargetException e) {
576             BPM.LOG.error("Invocation Target.", e);
577         } catch (final SecurityException e) {
578             BPM.LOG.error("Class could not be found.", e);
579         } catch (final NoSuchMethodException e) {
580             BPM.LOG.error("Class could not be found.", e);
581         }
582         taskService.complete(_taskSummary.getId(),
583                              EntityMapper.getUserId(Context.getThreadContext().getPerson().getUUID()), results);
584 
585         BPM.invokeAsyncListeners(AsyncCalls.AFTER_EXECUTE, _taskSummary, results);
586     }
587 
588     /**
589      * @param _taskSummary tasksummary the data is wanted for
590      * @return the object data
591      */
592     public static Object getTaskData(final TaskSummary _taskSummary)
593     {
594         Object ret = null;
595         final RuntimeEngine runtimeEngine = BPM.PMANAGER.getRuntimeEngine(ProcessInstanceIdContext.get(_taskSummary
596                         .getProcessInstanceId()));
597         final TaskService taskService = runtimeEngine.getTaskService();
598         final Task task = taskService.getTaskById(_taskSummary.getId());
599         final long contentId = task.getTaskData().getDocumentContentId();
600         if (contentId != -1) {
601             final Content content = taskService.getContentById(contentId);
602             ret = ContentMarshallerHelper.unmarshall(content.getContent(),
603                             runtimeEngine.getKieSession().getEnvironment(),
604                             BPM.class.getClassLoader());
605         }
606         return ret;
607     }
608 
609     /**
610      * @return list of assigned tasks
611      */
612     public static List<TaskSummary> getTasksAssignedAsPotentialOwner()
613     {
614         final List<TaskSummary> ret = new ArrayList<TaskSummary>();
615         final RuntimeEngine runtimeEngine = BPM.SMANAGER.getRuntimeEngine(EmptyContext.get());
616         final TaskService taskService = runtimeEngine.getTaskService();
617         try {
618             if (Context.getThreadContext().getPerson().getUUID() == null) {
619                 BPM.LOG.error("User '{}' has no UUID assigned.", Context.getThreadContext().getPerson().getName());
620             } else {
621                 final String persId = EntityMapper.getUserId(Context.getThreadContext().getPerson().getUUID());
622                 // final String language = Context.getThreadContext().getLanguage();
623                 ret.addAll(taskService.getTasksAssignedAsPotentialOwner(persId, "en-UK"));
624             }
625         } catch (final EFapsException e) {
626             BPM.LOG.error("Error on retrieving List of TaskSummaries.");
627         }
628         return ret;
629     }
630 
631     /**
632      * @return list of assigned tasks
633      */
634     public static List<TaskSummary> getTasksOwned()
635     {
636         final List<TaskSummary> ret = new ArrayList<TaskSummary>();
637         final RuntimeEngine runtimeEngine = BPM.SMANAGER.getRuntimeEngine(EmptyContext.get());
638         final TaskService taskService = runtimeEngine.getTaskService();
639         try {
640             if (Context.getThreadContext().getPerson().getUUID() == null) {
641                 BPM.LOG.error("User '{}' has no UUID assigned.", Context.getThreadContext().getPerson().getName());
642             } else {
643                 final String persId = EntityMapper.getUserId(Context.getThreadContext().getPerson().getUUID());
644                 // final String language = Context.getThreadContext().getLanguage();
645                 final List<Status> status = new ArrayList<Status>();
646                 status.add(Status.InProgress);
647                 status.add(Status.Reserved);
648                 status.add(Status.Suspended);
649                 ret.addAll(taskService.getTasksOwnedByStatus(persId, status, "en-UK"));
650             }
651         } catch (final EFapsException e) {
652             BPM.LOG.error("Error on retrieving List of TaskSummaries.");
653         }
654         return ret;
655     }
656 
657 
658     /**
659      * @param _processInstanceId ProcessInstance the task are wanted for
660      * @param _status status
661      * @return list of tasks
662      */
663     public static List<TaskSummary> getTasksByStatusByProcessId(final long _processInstanceId,
664                                                                 final List<Status> _status)
665     {
666         final List<TaskSummary> ret = new ArrayList<TaskSummary>();
667         if (BPM.processIsActiv(_processInstanceId)) {
668             final RuntimeEngine runtimeEngine = BPM.PMANAGER.getRuntimeEngine(ProcessInstanceIdContext
669                             .get(_processInstanceId));
670             final TaskService taskService = runtimeEngine.getTaskService();
671 
672             ret.addAll(taskService.getTasksByStatusByProcessInstanceId(_processInstanceId, _status, "en-UK"));
673         }
674         return ret;
675     }
676 
677     /**
678      * @param _processInstanceId ProcessInstance the task are wanted for
679      * @param _status status
680      * @param _taskName name of the task wanted
681      * @return list of tasks
682      */
683     public static List<TaskSummary> getTasksByStatusByProcessInstanceIdByTaskName(final long _processInstanceId,
684                                                                                   final List<Status> _status,
685                                                                                   final String _taskName)
686     {
687         final List<TaskSummary> ret = new ArrayList<TaskSummary>();
688         if (BPM.processIsActiv(_processInstanceId)) {
689             final RuntimeEngine runtimeEngine = BPM.PMANAGER.getRuntimeEngine(ProcessInstanceIdContext
690                             .get(_processInstanceId));
691             final InternalTaskService taskService = (InternalTaskService) runtimeEngine.getTaskService();
692             ret.addAll(taskService.getTasksByStatusByProcessInstanceIdByTaskName(_processInstanceId, _status, _taskName));
693         }
694         return ret;
695     }
696 
697     /**
698      * @param _taskSummary summary the task is wanted for
699      * @return internal task object
700      */
701     public static InternalTask getTaskById(final TaskSummary _taskSummary)
702     {
703         final RuntimeEngine runtimeEngine = BPM.PMANAGER.getRuntimeEngine(ProcessInstanceIdContext.get(_taskSummary
704                         .getProcessInstanceId()));
705         final TaskService taskService = runtimeEngine.getTaskService();
706         return (InternalTask) taskService.getTaskById(_taskSummary.getId());
707     }
708 
709     /**
710      * @return the TaskAdmin
711      */
712     public static TaskAdminstration getTaskAdmin()
713     {
714         final RuntimeEngine runtimeEngine = BPM.SMANAGER.getRuntimeEngine(EmptyContext.get());
715         final TaskService taskService = runtimeEngine.getTaskService();
716         return new TaskAdminstration((InternalTaskService) taskService);
717     }
718 
719     /**
720      * @return the TaskAdmin
721      */
722     public static ProcessAdmin getProcessAdmin()
723     {
724         final RuntimeEngine runtimeEngine = BPM.SMANAGER.getRuntimeEngine(EmptyContext.get());
725         return new ProcessAdmin(new JPAAuditLogService(runtimeEngine.getKieSession().getEnvironment()));
726     }
727 
728     /**
729      * Invoke the listener.
730      * @param _call call to be executed
731      * @param _taskSummary  tasksummary of the task involved
732      * @param _values values form eFaps
733      */
734     private static void invokeAsyncListeners(final AsyncCalls _call,
735                                              final TaskSummary _taskSummary,
736                                              final Map<String, Object> _values)
737     {
738         // exec esjp
739         try {
740             final Class<?> listenerClass = Class.forName("org.efaps.esjp.bpm.listener.ReviewListener", true,
741                             EFapsClassLoader.getInstance());
742             final IAsyncListener listener = (IAsyncListener) listenerClass.newInstance();
743 
744             final Object taskData = BPM.getTaskData(_taskSummary);
745 
746             final String userName = Context.getThreadContext().getPerson().getName();
747             final ListenerThread threat = new ListenerThread(userName,  listener, _call, _values, taskData);
748 
749             final BasicThreadFactory factory = new BasicThreadFactory.Builder()
750                             .namingPattern("eFapsBPMListenerThreat-%d")
751                             .priority(Thread.MIN_PRIORITY)
752                             .build();
753             final ExecutorService exec = Executors.newSingleThreadExecutor(factory);
754             exec.submit(threat);
755             exec.shutdown();
756 
757         } catch (final ClassNotFoundException e) {
758             BPM.LOG.error("Class could not be found.", e);
759         } catch (final InstantiationException e) {
760             BPM.LOG.error("Class could not be instantiation.", e);
761         } catch (final IllegalAccessException e) {
762             BPM.LOG.error("Class could not be accessed.", e);
763         } catch (final IllegalArgumentException e) {
764             BPM.LOG.error("Illegal Argument.", e);
765         } catch (final SecurityException e) {
766             BPM.LOG.error("Class could not be found.", e);
767         } catch (final EFapsException e) {
768             BPM.LOG.error("EFapsException catched", e);
769         }
770     }
771 
772     /**
773      * Threat to execute the listeners.
774      */
775     private static class ListenerThread
776         implements Runnable
777     {
778 
779         /**
780          * Listener to be executed.
781          */
782         private final IAsyncListener listener;
783 
784         /**
785          * Call to be executed on the listener.
786          */
787         private final AsyncCalls call;
788 
789         /**
790          * value mapping.
791          */
792         private final Map<String, Object> values;
793 
794         /**
795          * Data from the task.
796          */
797         private final Object taskData;
798         /**
799          * UserName the Context will be spanned for.
800          */
801         private final String userName;
802 
803         /**
804          * @param _userName userName
805          * @param _listener listener
806          * @param _call     call
807          * @param _values   values
808          * @param _taskData taskdata
809          */
810         public ListenerThread(final String _userName,
811                               final IAsyncListener _listener,
812                               final AsyncCalls _call,
813                               final Map<String, Object> _values,
814                               final Object _taskData)
815         {
816             this.userName = _userName;
817             this.listener = _listener;
818             this.call = _call;
819             this.values = _values;
820             this.taskData = _taskData;
821         }
822 
823         /**
824          * When an object implementing interface <code>Runnable</code> is used
825          * to create a thread, starting the thread causes the object's
826          * <code>run</code> method to be called in that separately executing
827          * thread.
828          * <p>
829          * The general contract of the method <code>run</code> is that it may
830          * take any action whatsoever.
831          *
832          * @see     java.lang.Thread#run()
833          */
834         @Override
835         public void run()
836         {
837             try {
838                 if (!Context.isTMActive()) {
839                     Context.begin(this.userName, false);
840                 }
841             } catch (final EFapsException e) {
842                 BPM.LOG.error("Context problem", e);
843             }
844             try {
845                 switch (this.call) {
846                     case AFTER_EXECUTE:
847                         this.listener.onAfterExecute(this.values, this.taskData);
848                         break;
849                     default:
850                         break;
851                 }
852             } catch (final EFapsException e) {
853                 BPM.LOG.error("execution problem", e);
854             } finally {
855                 try {
856                     if (!Context.isTMNoTransaction()) {
857                         if (Context.isTMActive()) {
858                             Context.commit();
859                         } else {
860                             Context.rollback();
861                         }
862                     }
863                 } catch (final EFapsException e) {
864                     BPM.LOG.error("Context problem", e);
865                 }
866             }
867         }
868     }
869 }