7 Replies Latest reply on Aug 3, 2006 8:16 PM by shane.bryzak

    WebRemote inconsistencies

    zeddmaxim

      Is there some sort of SOP I should follow when deploying an application that uses remote methods via WebRemote?

      When redeploying for testing, I have about a 50/50 chance that the @WebRemote methods will actually appear in the javascript stubs. (Half the time I get xxx method is not a function javascript errors.) Usually if I just rebuild and redeploy the EAR again, it works.

      Is this a known seam issue, or am I doing something incorrectly? Should I be shutting down and undeploying my ear before redeploying? I'm not posting code, because when it works, it works very well, so I doubt the code is the culprit in this instance. Enlightmen me if necessary.

      Steve

        • 1. Re: WebRemote inconsistencies
          shane.bryzak

          I've never come across this issue before. If you browse to the stubs directly do they only work intermittently?

          • 2. Re: WebRemote inconsistencies
            zeddmaxim

            Here are the two stubs, the first set is when it does not work, the second, when it does. All I do inbetween is rebuild the ear and redeploy it via MyEclipse IDE. I am using JBoss 4.0.4GA (installed via the JEMS installer) and Seam 1.0.1 GA if that helps any.

            Seam.Remoting.type.modelbuilder = function() {
             this.__callback = new Object();
            }
            Seam.Remoting.type.modelbuilder.__name = "modelbuilder";
            
            Seam.Component.register(Seam.Remoting.type.modelbuilder);


            Seam.Remoting.type.modelbuilder = function() {
             this.__callback = new Object();
             Seam.Remoting.type.modelbuilder.prototype.findGL = function(p0, callback) {
             return Seam.Remoting.execute(this, "findGL", [p0], callback);
             }
             Seam.Remoting.type.modelbuilder.prototype.getDefaultPOD = function(p0, callback) {
             return Seam.Remoting.execute(this, "getDefaultPOD", [p0], callback);
             }
             Seam.Remoting.type.modelbuilder.prototype.getPriceFactors = function(p0, callback) {
             return Seam.Remoting.execute(this, "getPriceFactors", [p0], callback);
             }
             Seam.Remoting.type.modelbuilder.prototype.validateModelDescription = function(p0, p1, p2, callback) {
             return Seam.Remoting.execute(this, "validateModelDescription", [p0, p1, p2], callback);
             }
            }
            Seam.Remoting.type.modelbuilder.__name = "modelbuilder";
            
            Seam.Component.register(Seam.Remoting.type.modelbuilder);


            • 3. Re: WebRemote inconsistencies
              shane.bryzak

              Is it possible for you to debug this? I can't reproduce it so any insight into its cause would be very helpful. You would need to set your breakpoint in InterfaceGenerator.appendComponentSource(). There's a while-loop that iterates through the methods of your component to add them to the javascript source:

              componentSrc.append("Seam.Remoting.type.");
               componentSrc.append(component.getName());
               componentSrc.append(" = function() {\n");
               componentSrc.append(" this.__callback = new Object();\n");
              
               for (Method m : type.getDeclaredMethods()) // <- set breakpoint here


              You would need to step through this code and see if its finding your component methods or not.

              • 4. Re: WebRemote inconsistencies
                zeddmaxim

                I think I have found the problem. It is mostly my fault, but I think a change or two in InterfaceGenerator.appendComponentSource() would ease a lot of people's headaches in the future.

                My WebRemote methods are in a SFSB, with both a remote and local interface. However, the remote and local interfaces are not the same (more methods are exposed via the local than remote, including my WebRemote methods). The culprit in this situation lies with the following snippet from that method:

                if ((component.getType().equals(ComponentType.STATEFUL_SESSION_BEAN) ||
                 component.getType().equals(ComponentType.STATELESS_SESSION_BEAN)) &&
                 component.getBusinessInterfaces().size() > 0)
                 {
                 type = component.getBusinessInterfaces().iterator().next();
                 }


                Since the method getBusinessInterfaces() returns a Set, which is not ordered, and I have 2 interfaces on my SFSB, I have (roughly) a 50/50 chance of getting my local interface returned first, which contains my WebRemote method stubs. If my remote interface is returned first, no stubs.

                The solution for me is easy at this point. Expose my WebRemote methods in the remote interface as well, and it then does not matter which it grabs first.

                However, in the long run, would it not make more sense to iterate all of the stateless/ful session bean's interfaces looking for WebRemote methods?

                Incidentally, I admit it is not a common use case to have your local and remote interfaces be different, but the case still seems valid.

                • 5. Re: WebRemote inconsistencies
                  zeddmaxim

                  Ok, so my understanding is still incomplete. Adding to the remote interface adds the stubs, but does not solve the problem. Does seam remoting only work with local interfaces? When the Call class actually invokes the method through reflection, I am getting the following stack trace:

                  java.lang.IllegalArgumentException: object is not an instance of declaring class
                   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
                   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
                   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
                   at java.lang.reflect.Method.invoke(Method.java:585)
                   at org.jboss.seam.remoting.Call.execute(Call.java:121)
                   at org.jboss.seam.remoting.ExecutionHandler.handle(ExecutionHandler.java:92)
                   at org.jboss.seam.remoting.SeamRemotingServlet.doPost(SeamRemotingServlet.java:56)
                   at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
                   at javax.servlet.http.HttpServlet.service(HttpServlet.java:810)
                   at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:252)
                   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:432)
                   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)


                  Also, I noticed this in Call.execute itself:

                  if (component.getBusinessInterfaces().size() > 0)
                   {
                   // Get the local interface for the component - this is the type that we're
                   // going to assume we're invoking against.
                   type = component.getBusinessInterfaces().iterator().next();
                   }


                  If you're only going after local interfaces, would it make more sense to iterate until you find one with a @Local annotation? Again, my understanding may be incomplete, and these suggestions may be totally bogus.

                  My solution for now will be to remove the remote interface. We had only been using it for testing up to this point. However, if the time ever comes that they want to expose this bean as a web service, or they want the class to implement another interface, this will again become a problem for me.

                  • 6. Re: WebRemote inconsistencies
                    shane.bryzak

                    Yes you're right, it should only use the Local interface. I'll modify InterfaceGenerator and the Call class today to ensure that they get only the interface annotated as @Local.

                    • 7. Re: WebRemote inconsistencies
                      shane.bryzak

                      All fixed. The local interface is now used in both places.