Human Task Module Refactoring

Version 7

    This document aims to explain how the human task module should look after applying some refactorings which were the results of several experiments.

    You can more about this experiments here: https://github.com/Salaboy/human-task-poc-proposal

     

    The following sections describe how the module will look like after the refactorings

     

    APIs and Service Structure

    All the Services Proposed by this refactoring are CDI managed beans. For the ones not familiar with CDI, you need to think about it as JPA for Dependency Injection frameworks. So we can say

    that CDI is to Spring/Guice/Weld what JPA is to Hibernate/Top Link. CDI propose some very cool out of the box features that we definitely want to use to make our services more clear, robust, easy to maintain. Some of the things provided by CDI that I'm using in the experiments are:

     

     

    At the end of the day we have a set of services which can leverage the power of the CDI container. We can also hide that we are using CDI/Weld (weld is the implementation of the CDI interfaces/spec), look at: https://github.com/Salaboy/human-task-poc-proposal/blob/master/human-task-core-cdi-experiment/src/test/java/org/jboss/human/interactions/NewAPITest.java#L259

    We can use it internally and if the user wants to get access to the container he/she can.

     

    TaskServicesProposed.png

    All the proposed services are simple POJOs which can contain references to all the other services. We can combine them to achive different functionality.

    For a more detailed description about each service you can look at: https://community.jboss.org/wiki/HumanTaskAPIAndDataStructuresProposal

     

    The next section describe more advantages about using the CDI/Weld proposed programming model to keep our services simple and take out all the code that is not related with Human Interaction logic.

     

     

    Services Working Together

    The following image shows how the interactions with the human task module will happen. The diagram shows the interfaces and implementations required to interact with a TaskInstance

    TaskInstanceServiceSimplified.png

    The previous figure shows all the components interacting when we want to interact with a task instance that was already created.

    So let's say for example that we want to start a task. From the client perspective he/she can use the TaskServiceEntryPoint to

    start the task. This TaskServiceEntryPoint will delegate the calls to the different service implementations. In this case if we are

    starting a task the TaskInstanceService implementation will delegate the action to the LifeCycleManager. As you can see

    the LifeCycleManager, no matter the implementation is being decorated by an UserGroupDecorator which in charge of handling the

    resolution of the identities associated with the operation. The LifeCycleManager is also an Event Producer, which means that is in charge

    of generating events to communicate to the external world the LifeCycle changes of each task. We can then attach external listeners to

    Observer these events to audit what is happening or as callback mechanisms to execute actions when a task is completed for example.

    Classes and Interfaces to look at this point:

    https://github.com/Salaboy/human-task-poc-proposal/blob/master/human-task-core-cdi-experiment/src/main/java/org/jboss/human/interactions/api/TaskServiceEntryPoint.java

    https://github.com/Salaboy/human-task-poc-proposal/blob/master/human-task-core-cdi-experiment/src/main/java/org/jboss/human/interactions/impl/TaskInstanceServiceImpl.java

    https://github.com/Salaboy/human-task-poc-proposal/blob/master/human-task-core-cdi-experiment/src/main/java/org/jboss/human/interactions/impl/TaskDefServiceImpl.java

    https://github.com/Salaboy/human-task-poc-proposal/blob/master/human-task-core-cdi-experiment/src/main/java/org/jboss/human/interactions/internals/lifecycle/MVELLifeCycleManager.java

     

    No magic, no complicated debug sessions, the services should be as straight forward as possible trying to following the sequence:

    TaskServiceEntryPoint ---(Delegate)--> Task*ServiceImpl -> Storage

     

    Shared Persistence Context and Transactional Behavior

    If you take a look at the previous links you will notice that all the Services, for example TaskInstanceServiceImpl and TaskDefServiceImpl are all using an Inject EntityManager.

    And there is no code related with transactions or loading and merging detached entities (em.getTransaction(), ut.begin(), em.merge()).

    The EntityManager that is being injected is being managed by Seam Persistence (ASL 2.0) (http://docs.jboss.org/seam/3/persistence/latest/reference/en-US/html_single/) which give us a transparent

    way of having all the advantages of the unified programming model of being in Managed and Transaction Persistence Context without the hassle of taking care of how to share different

    instances of an EntityManager or demarcate the transactions based on what is available in our context. Seam Persistence provide us a declarative way to deal with all this topics, and take all the code

    related with these tasks out of the Human Task Module. This also give us the possibility to integrate with Spring only configuring our environment and not changing our code

    (http://www.javaworld.com/javaworld/jw-05-2008/jw-05-spring-seam3.html)

     

    The Seam 3 Spring module give us all the integration that we can possible want and even more with Spring, no need to worry about that stuff at all: http://seamframework.org/Seam3/SpringModule

    All this stuff is already tested, decoupled, and the most important is out of our module!

    Integration with the Outside World

    Using CDI for the integration perspective is just great. Most of the integration frameworks out there have CDI integration which make exposing our services extremely easy and natural.

    I've created an experiment showing how we can do this with Switchyard/Camel, and most of this principles can be used for the Process/Rule engine as well:

    https://github.com/Salaboy/human-task-poc-proposal/tree/master/human-task-switchard

     

    The main focus of this project is to contain all the integration configuration required to expose our POJO services using different transports. I've being focused on JMS because it will allow

    us to have asynchronous interactions transparently.

     

    The following figure shows us teh Switchyard Declarative configuration which is using our CDI POJO services to define the integration points:

    subscribers.png

    The previous diagram is showing the following interaction and integration points:

    1. A client sending a JMS message wants to start a task
    2. The Switchyard container is exposing a JMS queue which is expecting "Action" messages
    3. As soon as we get one of this action messages, Switchyard picks the message and propagate it to the correspondant service
    4. We can register a listener that will observe the events being fired by our components (i.e. TaskLifeCycleEvents)
    5. As soon as one of these events is observed by our listener it will be redirected to a JMS topic which can contain multiple subscribers
    6. Any number of subscribers can pick up the message and do what they want with it

     

    More info: https://community.jboss.org/wiki/HumanTaskModuleSwitchYardIntegration

     

    NOTE: An Executor component can be used to pick the up the notification and execute callbacks. I'm right now creating a document which explains how this component can be used.

    This idea perfectly fits in this scenario. I will add the link as soon as the document is ready.

     

    Cool Facts:

     

    1. This experiment is just showing one of the possibilities of using Switchyard and the camel integration for handling async interactions in a very efficient way, without including code inside the Human Task Module. We are delegating all the interaction points to the Integration framework instead of adding complexity to the Human Task Logic.
    2. We can integrate with any transport in the same way and we can mix and match what we want. For example, we can recieve a REST call and send notifications via JMS
    3. Switchyard and all the services can run inside a SE or EE environment (because of CDI and its programming model)
    4. Is all based on configuration, so we can provide a set of well known configurations and let the users to customize that if they want
    5. Quartz for reminders, cron tasks and all of that comes for free
    6. Push us to use a clean programming model, leverage all the CDI features
    7. All this mechanisms are already tests, there are more connectors comming and the most important is out of our module!