1 2 Previous Next 16 Replies Latest reply on Jan 20, 2006 6:42 PM by gavin.king

    Feedback requested

    gavin.king

      In the beta 1 release of Seam, I fussed and worried about what was the best way to specify a jBPM transition. Eventually I settled on the @Transition annotation, like so:

      @Transition
      private String transition;
      
      
      @EndTask
      public String myActionListener() {
       transition = "approved";
       return "success";
      }


      In beta 2, I've discovered a few other things which are kinda similar. We need ways to:

      (1) Set the jBPM actorId
      (2) Set the conversation description and outcome for conversation switching
      (3) Set the conversation timeout


      And I'm quite sure new things like these will pop up as we evolve.

      Rather than introducing annotations for all these things, I'm now inclined toward a pattern like this:

      @In Transition transition;
      
      @EndTask
      public String myActionListener() {
       transition.setName("approved");
       return "success";
      }



      And:


      @In Actor actor;
      
      public String login() {
       ...
       actor.setId( user.userName() );
       return "success";
      }



      And so I've removed the @Transition annotation from CVS.

      One advantage of this is it lets me group related things (eg. converstaion switching stuff) into a single API, instead of spreading them across multiple annotations.

      Does anyone object to this, or think the previous approach was much better?


      P.S. Because I noticed that it was *very* common for people to make @EndTask methods which always resulted in the same transition, I'm also supporting the following:

      @EndTask(transition="approved")
      public String myActionListener() {
       return "success";
      }



        • 1. Re: Feedback requested
          robjellinghaus

          Hm. The second version confuses me in two ways. First, you have this:

          @In Transition transition;
          
          @EndTask
          public String myActionListener() {
           transition.setName("approved");
           return "success";
          }

          First, it looks like the transition object is only @In, not @In @Out. But it's pretty clear that myActionListener is trying to communicate some state outwards to the conversation. So why not @Out also? Or is @Out only for cases where new contextual objects might be outjected (as opposed to just side-effecting existing ones)?

          Second, is it assumed that there is only one unique @In Transition field in the bean? Is that always a good assumption? It seems a little fragile.

          Your first alternative seems like it's using fine-grained (primitive-valued) fields, one per piece of conversational / jBPM state, with distinct annotations per field. Your second alternative encodes the state information into objects, which are not really annotated at all, and apparently are expected to be unique in their bean. There might be a hybrid approach. Perhaps there's a JBPMState object, with transition and actorId properties, and you have
          @JBPM JBPMState jBPMState;
          @ConversationState ConversationState convState;

          It's a little redundant, but it's trying to avoid the "explosion of annotations" problem without creating hardcoded type-based assumptions that an @In Transition field is always used to control the current jBPM flow.

          Cheers!
          Rob

          • 2. Re: Feedback requested
            gavin.king

             

            First, it looks like the transition object is only @In, not @In @Out. But it's pretty clear that myActionListener is trying to communicate some state outwards to the conversation. So why not @Out also? Or is @Out only for cases where new contextual objects might be outjected (as opposed to just side-effecting existing ones)?


            Right, this is a byvalue/byreference question. You can change the state of an @In-jected object by calling its method. This is not side-effecty. It is how any variable in Java works :-)

            Second, is it assumed that there is only one unique @In Transition field in the bean? Is that always a good assumption? It seems a little fragile.


            By definition, there is a unique instance of the Seam component named "transition" in your conversation context. It don't matter how many times you inject it, it will always be the same one. Until you switch conversations, that is ;-)



            • 3. Re: Feedback requested
              rdewell

              Regarding conversations, JBPM, workflow annotations, etc..

              While appreciate that Seam is (hopefully just initially) standardizing on JBPM for most workflow functionality, what I would LOVE to see is Seam also support a more lightweight workflow engine that is geared towards a non-persistent workflow -- workflow conversations that are only dealing with a web-RUNTIME lifespan.

              I see a couple of opportunities here:

              1) Perhaps this "engine" could be implemented directly in Seam itself. The excellently flexible yet simple Spring WebFlow would be a natural design starting point.

              http://opensource.atlassian.com/confluence/spring/display/WEBFLOW/Home

              2) Abstract Seam's conversation state / transition annotations into something that is pluggable. Then, we can plug in our own conversation handling as service providers.

              3) Both 1 and 2...

              A little off topic, but perhaps something to keep in mind while working on JBPM integration, if you're not already.

              Ryan

              • 4. Re: Feedback requested
                gavin.king

                Actually we are already working on this stuff. (It was part of the original vision of Seam that we mapped out almost a year ago. Christian Bauer was especially keen on this stuff, for several years.)

                jBPM already runs in pure in-memory mode, all we really need to do is write the JSF navigation handler.

                The language looks like this:

                <conversation-definition name="editDocument">
                
                 <start-state name="get">
                 <transition name="notFound" to="get"/>
                 <transition name="success" to="edit"/>
                 </start-state>
                
                 <state name="edit" page="/editDocument.jsp">
                 <transition to="done"/>
                 </state>
                
                 <end-state name="done" page="/findDocument.jsp"/>
                
                 </conversation-definition>


                Note that with this, you probably won't need the @End annotation anymore :-)


                So the idea is that you will use the same workflow language for orchestrating:

                (1) the persistent, multi-user, longrunning PROCESS
                (2) the pure-in-memory, single-user CONVERSATION

                Yes, I would like to make this more pluggable in future. You should be able to integrate any workflow engine you like into Seam.


                • 5. Re: Feedback requested
                  robjellinghaus

                   

                  "gavin.king@jboss.com" wrote:
                  First, it looks like the transition object is only @In, not @In @Out. But it's pretty clear that myActionListener is trying to communicate some state outwards to the conversation. So why not @Out also? Or is @Out only for cases where new contextual objects might be outjected (as opposed to just side-effecting existing ones)?


                  Right, this is a byvalue/byreference question. You can change the state of an @In-jected object by calling its method. This is not side-effecty. It is how any variable in Java works :-)

                  Ya, I know. But it makes @Out seem kind of pointless. Why not do everything with side-effects? In other words, if @In(create="true") suffices to create a seam component and inject it, why not just do @In(create="true") and then side-effect away?

                  The Seam documentation says this in chap. 4:
                  Note that it is quite common for these annotations to occur together, for example:
                  @In(create=true) @Out private User currentUser;

                  This is exactly what I'm talking about. What is the point of @Out here? It seems like just as much of a no-op as my use of @Out for the jBPM state, since the component will be created by @In(create=true) and then just put back by the @Out. There's something I'm missing here, but what?

                  By definition, there is a unique instance of the Seam component named "transition" in your conversation context. It don't matter how many times you inject it, it will always be the same one. Until you switch conversations, that is ;-)

                  Where's that documented? I would've expected it in chapter 5 of the 1.0alpha reference docs, but didn't see it anywhere...?

                  Cheers!
                  Rob

                  • 6. Re: Feedback requested
                    gavin.king

                    OK, slow down. Take a deep breath.

                    Now forget everything you know about "dependency injection".

                    We are not doing dependency injection here. These are *stateful* components with *identity*. Think about Seam in terms of "contextual variables".

                    @In and @Out alias contextual variables to instance variables. By analogy with aliasing instance variables to local variables:

                    @In Foo foo;


                    Is similar to:

                    final Foo foo = this.foo;
                     ...


                    And:

                    @In @Out Foo foo;


                    is like:

                    Foo foo = this.foo;
                     ...
                     this.foo = foo;


                    The difference with @In @Out is that you are able to modify the value of the variable itself. ie. change the reference. With @In alone, you can only change the state of the referent.

                    With stateful components you sometimes simply can't "do everything with side-effects". For example:

                    currentUser = entityManager.merge(currentUser);


                    As for uniqueness, the whole *idea* of contextual components is that I have a unique instance of any particular component in "my current XXXXX context". Substitute EVENT, REQUEST, SESSION, CONVERSATION, PROCESS, APPLICATION or PAGE for XXXXX.

                    Think about "state", "context" and "identity" and how they relate to each other. These concepts are key to understanding anything in Seam. Seam components are true "objects" with state+behavior+identity. Stateless component models are by nature *not* object-oriented.

                    Seam components can even be runtime polymorphic! Stateless component models feature only configuration-time polymorphism. This is why you see the DI boosters making such a big deal about configuration/testing - it is because this is the only problem that DI actually solves!

                    It seems that too much experience of Spring and similar stateless component models has addled everybody's brains even worse than I feared! ;-)


                    • 7. Re: Feedback requested
                      robjellinghaus

                       

                      "gavin.king@jboss.com" wrote:
                      The difference with @In @Out is that you are able to modify the value of the variable itself. ie. change the reference. With @In alone, you can only change the state of the referent.

                      This is very clear and makes sense. I see where LoginAction.login() does this on a successful login.

                      As for uniqueness, the whole *idea* of contextual components is that I have a unique instance of any particular component in "my current XXXXX context". Substitute EVENT, REQUEST, SESSION, CONVERSATION, PROCESS, APPLICATION or PAGE for XXXXX.

                      And uniqueness is determined by @Name? Then how does "@In Transition transition;" work? It looks like uniqueness there is being determined by either field type (Transition) or field name (transition)...?

                      It seems that Seam's aliasing rules require you to design your beans' field names around the names of the contextual components you want to alias to. It'd be really nice to have some form of Seam inspector that let you easily view the contextual components in scope at any point.

                      I also note that you didn't mention where the standard Transition contextual component is documented... :-)

                      Cheers!
                      Rob

                      (p.s. Yes, I know this is all newbie talk. I'm just hoping it helps you all with planning your documentation and training!)

                      • 8. Re: Feedback requested
                        gavin.king

                        Uniqueness is predicated on the ordered pair of (Scope, context variable name).

                        Just like in EJB3, the default name of the contextual variable is the field name. But you can always specify it explicitly if you like:

                        @In("foo") Foo bar;


                        Transition is new in CVS. I have not yet documented Seam 1.0 beta 2 features (they are still under development).

                        • 9. Re: Feedback requested
                          robjellinghaus

                          Great, thanks, no more questions. (on this thread, anyway ;-)

                          • 10. Re: Feedback requested
                            gavin.king

                            OK, so, at least for conversation descriptions and timeouts, I've taken a whole new tack now. I hated seeing conversation.switchableOutcome() everywhere in the example apps, and I could not quite figure out why. It just *felt* ugly and wrong.


                            Now I've decided that this stuff is really metadata about the "state". The "state" is welldefined when you are using jPDL pageflows, so you can just write stuff like:

                            <page name="browse" view-id="/brows.xhtml" timeout="300000">
                             <description>Search results for: #{search.searchPattern}</description>
                             <transition name="select" ... />
                            </page>


                            Unfortunately, for the case of JSF navigation, we have a stateless navigation model, where there are welldefined transitions, but no welldefined *sates*. Upon reflection of this issue, I decided that it is OK to use the closest thing to a state in JSF, which is the page.

                            Now, JSF has no such thing as a place to put metadata about a page, so I added the concept of a pages.xml file, which lives next to faces-config.xml in the WEB-INF directory.

                            Here is an example:

                            <pages>
                             <page view-id="/main.xhtml" timeout="300000">Search hotels: #{hotelBooking.searchString}</page>
                             <page view-id="/hotel.xhtml" timeout="300000">View hotel: #{hotel.name}</page>
                             <page view-id="/book.xhtml" timeout="600000">Book hotel: #{hotel.name}</page>
                             <page view-id="/confirm.xhtml" timeout="600000">Confirm: #{booking.description}</page>
                            </pages>


                            This essentially defines the states (well, "non-states") that the navigation rules refer to. And this means that I now have a welldefined notion of a switchable target state.

                            * Using JSF navigation, it is the ordered pair (view-id, conversationId)
                            * using jPDL navigation, it is the order pair (page node name, conversationId)

                            And, with this well-defined, Seam is now able to completely take care of the book-keeping needed to support conversation switching.

                            This let me *really* clean up the code of the booking and issues example apps.

                            • 11. Re: Feedback requested
                              gavin.king

                              By the way, it's becoming clear to me how much more pwerful jPDL navigation is than JSF navigation :-)

                              • 12. Re: Feedback requested
                                maxandersen

                                If I want to provide a more dynamic page title is that still possible ?

                                • 13. Re: Feedback requested
                                  gavin.king

                                  Oh. Hehe.

                                  I should mention that the #{....} stuff is not a reference to resource bundle-y stuff.

                                  They are EL expressions that are evaluated at runtime against the Seam components.

                                  Cool or what? :-)

                                  • 14. Re: Feedback requested
                                    maxandersen

                                    ..and i guess these seam components can evaluate/reason on to what view-id that is relevant - then yes, its cool ;)

                                    1 2 Previous Next