Web Services and Seam

Let’s say you have a Seam application, and you need to create some web services that tie in to it, or you are building a web service and you would like to take advantage of the Seam component model, lifecycle management, etc…

How do you expose Seam functionality through web services? Let’s dive into it:

First off, I’ve started with JBoss 4.0.5, JBoss Web Services 1.2.0, and Seam 1.2.0 (although 1.2.1 should work fine as well).

The first step is to create a class which will actually expose the web services. This class is NOT a Seam component. Create a method for each web service call you want exposed. For instance: getValueA(), getValueB, calculateSomething(int pNumberOne, int pNumberTwo)

Build out the methods, use the Seam Component class (org.jboss.seam.Component) to get access to your Seam components which hold the values or functionality you are trying to expose. This might look something like this:


public int calculateSomething(int pNumberOne, int pNumberTwo) {
   NumberCalculator calculator = (NumberCalculator)   Component.getInstance("numberCalculator", true);
   int result = calculator.calculateCost(pNumberOne, pNumberTwo);
   return result;
}

Where the NumberCalculator is your Seam component, named numberCalculator, which is actually going provide the logic.

Next, we need to annotate this class to let JBoss Web Services know you want to expose these methods as a web service. First, annotate the class with:

@WebService
@SOAPBinding(style = SOAPBinding.Style.RPC)

Where WebService is javax.jws.WebService, and SOAPBinding is javax.jws.soap.SOAPBinding. (If you have Eclipse, or a similar IDE, and JBoss WebServices in your project classpath, it will auto import the correct classes for the annotations.)

Next, annotate each method you want exposed with this:

@WebMethod

Where WebService is javax.jws.WebMethod.

The next step will be to setup the web.xml. There are two parts to this. First, we have to define the location of the web service, like this:


    
        CalculatorService
        com.digitalsanctuary.calculator.CalculatorWS
    
    
        CalculatorService
        /calculatorService
    

Then we need to ensure that when this class gets called, the Seam context is there for us, to allow Component to access your Seam components. We do that like this:


     
        Seam Servlet Filter 
        org.jboss.seam.servlet.SeamServletFilter 
     
    
     
        Seam Servlet Filter 
        /calculatorService 
      

Once you deploy your application, the web service should show up here:

http://localhost:8080/jbossws/services

This will also provide links to the wsdl (which you can use to generate your clients).


Posted

in

, ,

by

Tags:

Comments

8 responses to “Web Services and Seam”

  1. Arjan van Bentem Avatar
    Arjan van Bentem

    The new Seam 1.3 SeamBay example does it slightly different. Note that Seam 1.3 is currently only available from CVS, and web services is work in progress (I had to use a TinyURL as the JBoss forum URL was not understood by the preview).

    In CVS, AuctionService only uses @WebService and @WebMethod, and implements AuctionServiceRemote which uses @Remote. No further configuration in web.xml, but an additional configuration file META-INF/standard-jaxws-endpoint-config.xml which is included in the JAR file.

    This gets one odd URI’s such as /seam-bay-seam-bay/AuctionService (the web site being available at /seam-bay, this name is simply duplicated to get a unique URL). I don’t know where this is defined; maybe one needs to change web.xml after all to get custom URLs.

    See also the JBossWS User Guide and the JAX-WS Endpoint Configuration wiki pages.

  2. Devon Avatar

    I’ll have to check out the Seam 1.3 builds. I haven’t had time to look at the CVS build in a while. Thanks! I’ll check it out!

    Devon

  3. Arjan van Bentem Avatar
    Arjan van Bentem

    As for the odd URLs: when using JBoss AS 4.2.0.GA (instead of 4.2.0.RC1 which was current in April 2007) then one gets better URLs, which no longer hold the context name, but the class name instead.

    For example, for org.jboss.seam.example.seambay.AuctionService JBoss AS (or actually: jbossws-1.2.1.GA which is included in AS 4.2.0.GA) now generates

    http://127.0.0.1:8080/AuctionServiceService/AuctionService?wsdl

    So: neither the package name nor the context name are used, whereas the application itself could still be hosted at

    http://127.0.0.1:8080/seam-bay/home.seam

    I have not yet figured out if one can control the names JBoss chooses — I’d rather not rely on JBoss AS choosing a different name if ever upgrading the application server. As a first start, to avoid the double word “Service” maybe one should no longer name the service endpoint classes XYZService…

    Finally: please not that apparently I linked to an old version of the User Guide above; for jbossws-1.2.0 and higher the JBoss JAX-WS User Guide as found at the wiki should be used.

    Arjan.

  4. Devon Avatar

    Arjan,

    very cool! Thank you very much for following up on that. I really need to checkout the newer stuff. I tried moving my 10MinuteMail app over to the newer Seam running on 4.2.0 GA, but the server hangs while booting up. Remove the ear and it’s fine. No error messages, just locks up. I haven’t had the time to dive too deeply into it and pull stacktraces and the like.

    Wish me luck!

    Regards,

    Devon

  5. Arjan van Bentem Avatar
    Arjan van Bentem

    Ok, some more information…

    The META-INF/standard-jaxws-endpoint-config.xml file is the default filename as part of a JBoss proprietary annotation, @EndpointConfig. It has it’s own documentation page on the wiki, which took me some time to find but actually is linked in the “Appendix A” section of the JBoss JAX-WS User Guide. It doesn’t help me much but might have been enhanced by the time someone reads this…

    The client side has its own default file, standard-jaxws-client-config.xml.

    One might be able to change the URLs by using @WebContext, which is another JBoss proprietary annotation. However, some bug report (find JBWS-1622 or copy http://tinyurl.com/yv3da8 — the preview gets confused by too many URLs or something?) might indicate that this only changes the URL in the generated WSDL, not the URL of the WSDL itself. It also strikes me as odd to define the context root in the Java code… I did not try this.

    The @WebContext annotation might also be a (temporary) solution when deploying multiple web services, at which point one might encounter “Multiple context root not supported” errors. The solution states:

    Just make sure all EJB’s within a jar point to the same web context thriugh something like:
    @WebContext(contextRoot=”/myEJBServices”)

    Well, that’s it for today…!
    Arjan.

  6. Arjan van Bentem Avatar
    Arjan van Bentem

    Alright, I’ll consider this to be my personal blog ;-)

    First some other notes from Heiko Braun in the very same forum post, which are worth repeating here:

    I will try to explain what changes between 1.2.0 and 1.2.1 are causing the problems you encounter.
    For EJB3 deployments we need to create a web app for HTTP invocations (obviously)
    EJB’s don’t contain web context information, so we derive it automagically.
    Until 1.2.0 the context name was derived from the ear/jar name.
    This changed with 1.2.1 to an algorithm that derives it from the bean class name
    So what’s happening when you deploy a EJB3 jar that contains multiple beans?

    The default algorithm derives different context names for each bean in this deployment, which in turn we cannot use to setup the HTTP endpoint and thus throw an exception.

    This also explains why the following did work:
        @WebContext(contextRoot="/beans")

    Unfortunately this is left out in the specs and thus has been changed many times.

    Until we a have a definite solution i suggest you refer to the @WebContext annotation, even though it’s not the most elegant solution.

    And to use it: it’s org.jboss.ws.annotation.WebContext as found in jbossws-core.jar.

    This also invalidates some comment at the bug I mentioned, which made me write “[..] might indicate that this only changes the URL in the generated WSDL, not the URL of the WSDL itself“, which is NOT true. So, the following works just fine (in AS 4.2.0.GA, and if META-INF/standard-jaxws-endpoint-config.xml is present):

    // Service Endpoint Interface
    @WebService
    public interface DeepThoughtSEI {
      @WebMethod
      public String answer(String question);
    }

    and

    @Stateless
    @WebContext(contextRoot = "/guide/to/the/galaxy")
    @WebService(endpointInterface = "my.package.DeepThoughtSEI")
    public class DeepThought implements DeepThoughtSEI {
      public String answer(String question){
        return "42";
      }
     
      public String methodNotExposed(){
        return "not for public use";
      }
    }

    This serves the WSDL at http://universe.tld/guide/to/the/galaxy/DeepThought?wsdl — but I guess it’s to be considered a workaround.

    Note that when not specifying a value for endpointInterface then ALL methods in the DeepThought implementation would be exposed, unless at least one method is explicitly annotated in that class — even though the interface explicitly only declares a single method to be exposed. In other words: the @WebMethod annotations in the interface are only honored when endpointInterface is used.

    And for those who get to this page because of the “Multiple context root not supported” error: that might also be caused by some left-overs after refactoring. I changed the name of my service, leaving the old compiled classes in various exploded EAR folders, which were then still loaded by JBoss…

    Peek at the SeamBay example!

    Enjoy,
    Arjan.
    — the preview or stylesheet needs something to post pre-formatted code!

  7. hashem Avatar

    What about JWSDP besides seam and Jboss?!!!
    I have just started WebService! I started by sun’s JAX-RPC sample and I was able to call the service(in an standalone java application) after spending fairly acceptable time!
    So far so good, but when I try to use the same method in my web application to call the service, I get an untraceable error!!! (NOClassDefError)

    Now I want to see if it is possible to call my service using sun’s jwsd inside JBOSS in my seam based application? if so, which libraries do I need to put and in where!!?

  8. Ale Feltes Avatar

    Hello Devon. Following your guide, I almost got a web service running, just got an error at consuming the service, because I’m using Seam 2.x and Java 6, but thanks to these issue at jboss site, I got it all up and running.

    https://issues.jboss.org/browse/JBWS-1439?focusedCommentId=12460326#action_12460326

    — quote —
    copy below jar files from the JBOSS_HOME/client directory to the JBOSS_HOME/lib/endorsed
    jbossws-native-saaj.jar, jbossws-native-jaxrpc.jar, jbossws-native-jaxws.jar, jbossws-native-jaxws-ext.jar
    –quote —

Leave a Reply

Your email address will not be published. Required fields are marked *

PHP Code Snippets Powered By : XYZScripts.com