splitting the interfaces per use case ?
tom.baeyens Jun 23, 2008 7:54 AMPVM API's are used in 3 different scenarios:
1) an external client that starts new executions and provides external triggers into existing executions.
2) activity implementations will define the runtime behaviour of nodes.
3) event listeners (aka actions in jpdl3) that are used to associate java code to process events.
The main concept in common to all these 3 is the execution. There are 2 strategies to shaping the API:
a) One Execution interface that is used by all 3 use cases. This results into the design that is currently in svn pvm project.
The motivation for this is that the most common scenario is the easiest one to implement, namely automatic activities.
In the current design, you can implement an Activity (e.g. doing some kind of database or SAP update) and then use that implementation as the behaviour in a node or as an event listener.
The default proceed behaviour makes sure that this can be done and matches the behaviour of the exception handlers.
The current design does not force the implementor to start working with try-finally blocks in their activity implementations in this most common scenario.
b) we can also move to separate interfaces for each use case
interface ClientExecution { ...execution operations exposed to clients... }
interface ActivityExecution { ...execution operations exposed to Activity implementations... } interface Activity { void execute(ActivityExecution execution) }
interface EventListenerExecution { ...execution operations exposed to EventListener implementations... } interface EventListener { void notify(ActivityExecution execution) }
this has as an advantage that in each use case only the available methods are exposed.
the downside is that you get much more interfaces which represent the same concept. that can become confusing.
also, it will be a bit harder to implement the most common use case where people want to plug in a piece of automatic java code. they would have to do something like this:
class MyActivity implements Activity, EventListener { public void execute(ActivityExecution execution) { notify((ActivityExecution)execution); } public void notify(ActivityExecution execution) { ...do automatic things... } }
in a certain way this is cleaner. but the difference is that we're dealing with 3 use cases on the same object model. so i'm not so sure that providing completely separated API's for these 3 use cases is a good idea.
for the beginning user, i think it's the easiest if there is one activity interface for event listeners and for activity implementations. splitting the current single Execution into an ActivityExecution and an EventListenerExecution will create more confusion then it solves.
for the most common use case i also think that having a single Activity interface is the easiest way for users to get their automatic activities hooked into the process as node behaviour or as event listener.
i will still have to examine how the duplication of the execution interface per use case will relate to the process definition model.