10 Replies Latest reply on Oct 11, 2006 4:49 AM by pmuir

    Assigning an Actor for SEAM-jBPM integration

      Hi,

      I want to use SEAM and jBPM together, which seems simple enough, but I've come to realize that setting the "actor" component is absolutely critical to getting it to work.

      I've read through a number of threads on this forum and seen a number of posts saying "follow the examples".

      The problem is that the examples (todo, dvdstore) all require a SEAM specific login process, while I am forced to use HTTP basic during testing, and CAS (a single sign-on solution, found at http://www.ja-sig.org/products/cas/).

      I've bought and read the JBoss SEAM: Simplicity and Power Beyond Java EE and it doesn't go into much detail on this subject.

      So I'm wondering, what's the best way to set the actor without needing a SEAM specific login page?

      Thanks,

      Barry

        • 1. Re: Assigning an Actor for SEAM-jBPM integration
          pmuir

          I would assume that at some point you make the user (username at the very least) accessible as a Seam managed object - i.e. you have devised a way of knowing, within seam, who is logged in.

          So just add the Actor bit to that e.g.

          @Out(scope=SESSION)
          User currentUser;
          ...
          @Factory("currentUser")public void loginToSeam() {
           String username = retrieveCurrentUserFromCustomLoginMethod().getUserName();
           currentUser = em.find(User.class, username);
           Actor.instance.setId(username);
          }


          Then make sure you reference currentUser on the first (every?) page to be hit (you could have a non-rendered outputText for example).

          Though maybe the new security api will have hooks for this sort of thing in?

          • 2. Re: Assigning an Actor for SEAM-jBPM integration
            gavin.king

            Yep, petemuir has got it. Basically, using @Factory or @Unwrap, you can write a component that "pulls" data when you need it. You could even subclass Actor and replace the built-in component with one that automagically populates the actor id from the user principal.

            :-)

            • 3. Re: Assigning an Actor for SEAM-jBPM integration

              OK, I was wondering whether something like a servlet filter could do the job, access the Actor in the session context used by Seam, thus avoiding the need for the reference in the JSF page.

              I've tried petemuir's approach, but I must be missing something basic. I have a stateless session bean:

              @Stateful
              @Scope(SESSION)
              @SecurityDomain("ctSecDom")
              @Name("todoList")
              public class TaskSession implements TaskSessionLocal, TaskSessionRemote {
              
               private static final Logger LOGGER = Logger.getLogger( TaskSession.class);
              
              @Out(scope=SESSION)
              private String currentUser;
              
              @Factory("currentUser")public void loginToSeam() {
               LOGGER.fatal( "loginToSeam() called" );
               String username = "testuser";
               currentUser = username;
               Actor.instance().setId(username);
              }
              
              ...
              


              in my XHTML page, I have:

              <f:view>
               <h:form id="plist">
               <h:outputText value="Actor: #{todoList.currentUser}" />
               <div style="border-style: solid; border-width: 1px; border-color: #0000ff; padding: 8px">
               <h1>Pooled To-Do Items</h1>
              ...
              


              but when I enter the URL in the browser, I get the exception:


              22:07:47,872 ERROR [STDERR] Oct 9, 2006 10:07:47 PM com.sun.facelets.compiler.TagLibraryConfig loadImplicit
              INFO: Added Library from: jar:file:/home/bsheward/platform/trunk/jboss/server/default/deploy/ctp.ear/ctpwebapp.war/WEB-INF/lib/jsf-facelets-1.jar!/META-INF/jstl-core.taglib.xml
              22:07:48,173 ERROR [RendererUtils] Property not found - called by component : {Component-Path : [Class: javax.faces.component.UIViewRoot,ViewId: /utils/taskAdmin.xhtml][Class: javax.faces.component.html.HtmlForm,Id: plist][Class: javax.faces.component.html.HtmlOutputText,Id: _id1]}
              22:07:48,174 ERROR [STDERR] Oct 9, 2006 10:07:48 PM com.sun.facelets.FaceletViewHandler handleRenderException
              SEVERE: Error Rendering View[/utils/taskAdmin.xhtml]
              javax.faces.el.PropertyNotFoundException: /utils/taskAdmin.xhtml @14,58 value="Actor: #{todoList.currentUser}": Bean: $Proxy152, property: currentUser
              at com.sun.facelets.el.LegacyValueBinding.getValue(LegacyValueBinding.java:58)
              at javax.faces.component.UIOutput.getValue(UIOutput.java:75)
              at org.apache.myfaces.renderkit.RendererUtils.getStringValue(RendererUtils.java:225)
              at org.apache.myfaces.renderkit.html.HtmlTextRendererBase.renderOutput(HtmlTextRendererBase.java:65)
              at org.apache.myfaces.renderkit.html.HtmlTextRendererBase.encodeEnd(HtmlTextRendererBase.java:53)
              ...


              Shouldn't the valid of currentUser be outjected when the JSF needs to render it? What is the exception message actually telling me?

              Any assistance would be gratefully appreciated!

              Barry

              • 4. Re: Assigning an Actor for SEAM-jBPM integration
                gavin.king

                Change #{todoList.currentUser} to #{currentUser}

                • 5. Re: Assigning an Actor for SEAM-jBPM integration

                  Hhhmmm....

                  Not really sure why that needed to change. I now see this exception:


                  java.lang.IllegalArgumentException: create method not found
                  at org.jboss.seam.Component.callComponentMethod(Component.java:1342)
                  at org.jboss.seam.Component.getInstanceFromFactory(Component.java:1293)
                  at org.jboss.seam.Component.getInstance(Component.java:1260)
                  at org.jboss.seam.Component.getInstance(Component.java:1246)
                  at org.jboss.seam.jsf.SeamVariableResolver.resolveVariable(SeamVariableResolver.java:44)
                  at com.sun.facelets.el.LegacyELContext$LegacyELResolver.getValue(LegacyELContext.java:134)
                  at com.sun.el.parser.AstIdentifier.getValue(AstIdentifier.java:65)
                  at com.sun.el.parser.AstDeferredExpression.getValue(AstDeferredExpression.java:46)
                  at com.sun.el.parser.AstCompositeExpression.getValue(AstCompositeExpression.java:51)
                  at com.sun.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:192)
                  at com.sun.facelets.el.TagValueExpression.getValue(TagValueExpression.java:71)
                  at com.sun.facelets.el.LegacyValueBinding.getValue(LegacyValueBinding.java:56)
                  at javax.faces.component.UIOutput.getValue(UIOutput.java:75)
                  at org.apache.myfaces.renderkit.RendererUtils.getStringValue(RendererUtils.java:225)
                  at org.apache.myfaces.renderkit.html.HtmlTextRendererBase.renderOutput(HtmlTextRendererBase.java:65)
                  at org.apache.myfaces.renderkit.html.HtmlTextRendererBase.encodeEnd(HtmlTextRendererBase.java:53)
                  at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:331)
                  at com.sun.facelets.tag.jsf.ComponentSupport.encodeRecursive(ComponentSupport.java:242)
                  at com.sun.facelets.tag.jsf.ComponentSupport.encodeRecursive(ComponentSupport.java:239)
                  at com.sun.facelets.tag.jsf.ComponentSupport.encodeRecursive(ComponentSupport.java:239)
                  at com.sun.facelets.FaceletViewHandler.renderView(FaceletViewHandler.java:554)
                  at org.apache.myfaces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:352)
                  at javax.faces.webapp.FacesServlet.service(FacesServlet.java:107)
                  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:252)
                  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
                  at org.jboss.seam.servlet.SeamRedirectFilter.doFilter(SeamRedirectFilter.java:30)
                  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:202)
                  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
                  at org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
                  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:202)
                  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
                  at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
                  at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:178)
                  at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:175)
                  at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:524)
                  at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:74)
                  at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:126)
                  at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)
                  at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:107)
                  at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)
                  at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:869)
                  at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:664)
                  at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:527)
                  at org.apache.tomcat.util.net.MasterSlaveWorkerThread.run(MasterSlaveWorkerThread.java:112)
                  at java.lang.Thread.run(Thread.java:595)
                  Caused by: java.lang.NoSuchMethodException: $Proxy152.loginToSeam()
                  at java.lang.Class.getMethod(Class.java:1581)
                  at org.jboss.seam.Component.callComponentMethod(Component.java:1331)
                  ... 44 more


                  Thanks very much for your help!

                  Barry

                  • 6. Re: Assigning an Actor for SEAM-jBPM integration
                    pmuir

                    Make sure loginToSeam is declared on the (local) interface.

                    Why did that need to change? Well #{todoList.currentUser} ~= todoList.getCurrentUser() - which is method (property) you don't have whilst #{currentUser} references the variable referenced by the @Out (which is therefore intialised by the @Factory method)

                    • 7. Re: Assigning an Actor for SEAM-jBPM integration

                      Thanks! Declaring loginToSeam() in the local interface did the trick!!

                      I'm sorry I still don't get how I can omit the todoList from the #{currentUser}. How does JSF/Seam know which object it should be instantiating in order to provide the currentUser property?

                      I thought that when the JSF needs to render and comes across a property, it uses the @Name("xxx") to determine the object to instantiate, in my case, todoList is the name of the TaskSession object. So Seam uses reflection and the annotations to detemine that it needs to run the factory method and outject the currentUser property. I don't see how it can do that without knowing the object to instantiate, via the reference to the object's @Name.

                      Am I missing something obvious?

                      Again, thanks for the help!

                      • 8. Re: Assigning an Actor for SEAM-jBPM integration
                        pmuir

                        This is covered (fairly extensively!) in the examples/reference manual.

                        @Name("todoList")
                        public class TodoListBean {
                        
                        @Out(scope=SESSION)
                        User currentUser;
                        
                        @Factory("currentUser")
                        // Continue as above
                        }


                        #{currentUser}


                        OR

                        @Name("todoList")
                        public class TodoListBean {
                        
                        User currentUser;
                        
                        public User getCurrentUser() {
                         // Initialise currentUser
                         return currentUser;
                        }
                        ...
                        }


                        #{todoList.currentUser}


                        • 9. Re: Assigning an Actor for SEAM-jBPM integration

                          petemuir,

                          Thanks so much for your help. I've re-read the reference guide at http://docs.jboss.com/seam/latest/reference/en/html/tutorial.html#registration-example and I think I figured out where I was going wrong.

                          I found this:


                          1.3.2. How it works

                          The first time we navigate to the messages.jsp page, whether by a JSF postback (faces request) or a direct browser GET request (non-faces request), the page will try to resolve the messageList context variable. Since this context variable is not initialized, Seam will call the factory method findMessages(), which performs a query against the database and results in a DataModel being outjected. This DataModel provides the row data needed for rendering the <h:dataTable>.


                          So, this implies that Seam knows which session bean to instantiate in order to get the @Out messageList context variable, without needing to be told.

                          You don't need to use #{messageManager.messageList} because Seam knows to use the session bean declared with @Name("messageManager") to get the value of messageList to be outjected.

                          Alternatively, Seam can instantiate the session bean declared with in @Name("todoList") but without outjected fields. These beans are part of the Seam context, and can have methods run against them, using the #{todoList.method} syntax.

                          Am I now thinking along the right lines?

                          • 10. Re: Assigning an Actor for SEAM-jBPM integration
                            pmuir

                            Exactly.