5 Replies Latest reply on Jun 26, 2008 7:40 AM by thomas.diesler

    splitting the interfaces per use case ?

    tom.baeyens

      PVM 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.

        • 1. Re: splitting the interfaces per use case ?
          heiko.braun

          http://en.wikipedia.org/wiki/Separation_of_concerns

          On a per use case basis, there will only be 1single relevant interface.
          The overall number of artifacts doesn't matter that much, IMO.

          So, I'd say make it three separate interfaces.

          • 2. Re: splitting the interfaces per use case ?
            tom.baeyens

             

            "heiko.braun@jboss.com" wrote:
            On a per use case basis, there will only be 1single relevant interface.


            which one are you referring to ?

            "heiko.braun@jboss.com" wrote:
            The overall number of artifacts doesn't matter that much, IMO.


            It's not just the number. It's the : "how much do devs have to learn before they can get started?" and the : "How much ways are there to get it wrong?" Both should be as minimal as possible for the simple and most common cases.

            It would be great if you could check out exception handling and the default proceed behaviour.

            Those are build in combination to make it easy to implement automatic activities.


            In the meantime, i'll see to what extend these interfaces can be split without splitting the references to process definition interfaces.

            Thomas was referring to minimal API. A lot of the interfaces in PVM are process definition information which is mostly unused. I only made functionality unavailble if i was in doubt. I'll take the reverse angle now and only make the process definition element available if it must be abailable.

            • 3. Re: splitting the interfaces per use case ?
              tom.baeyens

              While splitting the interfaces, I see more and more different use cases of the execution.

              * parameter in activity methods
              * parameter in even listener notify method
              * parameter in a condition
              * return value in session facade methods
              * programmatic (non-persistent) client

              If we split the execution on a use case basis, we might end up with loads of execution interfaces. and some of them might actually be the same. in that case naming becomes an issue.

              I just wanted to bring up this point. I'll keep exploring this route of splitting the interfaces.

              • 4. Re: splitting the interfaces per use case ?
                tom.baeyens

                Another problem is the related controllers. An execution can optionally have an ActivityInstance. When an activity instance is present, all triggers have to go through this activity instance.

                This means that we have to propagate the splitting of the interfaces over to aggregated classes. So we should create a ClientActivityInstance, ActivityActivityInstance, EventListenerActivityInstance,...

                Should we create separate getters for each individual return type ?

                • 5. Re: splitting the interfaces per use case ?
                  thomas.diesler

                  This thread is jumping ahead. All API discussion should be based on http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4160822#4160822

                  To make a suggestion on how a particular functionality could be handled through the API, we need to see a sample test case that exercises the API in a particular way. We will however not compromise correctness for the sake of having less interfaces.

                  Things should be a simple as possible, but not simpler
                  - A. Einstein