1 Reply Latest reply on Aug 31, 2011 8:26 PM by cosmo

    Web Services SEAM + CXF + Tomcat (no JBoss Embedded)

    jwisnie1

      Web Services SEAM, CXF, Tomcat (no JBoss Embedded)





      So finally, after 3 days, I think I got it right. There is not much info on the web about running web services on seam and tomcat, when no ejb's are availible, so i thought i post a little tutorial. I'am not sure this is the proper configuration, so any comments would be appriciated. Nevertheles it seems to work.


      System configuration:


      CXF 2.4.2, SEAM 2.2.2 Final, Tomcat 6.0.32, JDK 1.6.0-26





      WEB-INF/lib:


      activation.jar, ant-antlr.jar, antlr.jar, antlr-runtime.jar, aopalliance-1.0.jar, asm-3.3.jar, axis.jar, backport-util-concurrent.jar, blazeds-common.jar, blazeds-core.jar, blazeds-proxy.jar, blazeds-remoting.jar, bsh.jar, cglib-2.2.jar, cglib-nodep.jar, commons-beanutils-1.8.2.jar, commons-codec.jar, commons-collections-3.1.jar, commons-dbcp-1.2.2.jar, commons-digester-1.8.1.jar, commons-discovery-0.2.jar, commons-httpclient.jar, commons-io.jar, commons-lang.jar, commons-lang-2.6.jar, commons-logging.jar, commons-logging-1.1.1.jar, commons-modeler-2.0.1.jar, commons-pool-1.3.jar, commons-validator-1.3.1.jar, concurrent.jar, core.jar, cxf-2.4.2.jar, cxf-xjc-boolean-2.4.0.jar, cxf-xjc-bug671-2.4.0.jar, cxf-xjc-dv-2.4.0.jar, cxf-xjc-ts-2.4.0.jar, darkX-3.3.3.Final.jar, datatypes.dtd, dbunit.jar, dom4j.jar, dom4j-1.6.1.jar, drools-api.jar, drools-compiler.jar, drools-core.jar, drools-decisiontables.jar, drools-templates.jar, DynamicJasper-3.0.16.jar, ehcache.jar, ehcache-1.5.0.jar, ejb-api.jar, el-api.jar, el-impl-1.0.jar, emma.jar, FastInfoset-1.2.9.jar, geronimo-jaxws_2.2_spec-1.0.jar, geronimo-ws-metadata_2.0_spec-1.1.3.jar, glassX-3.3.3.Final.jar, groovy-all.jar, guice.jar, gwt-servlet.jar, hibernate3.jar, hibernate-jpa-2.0-api-1.0.0.Final.jar, hibernate-validator.jar, html_basic.tld, htmlparser.jar, httpclient.jar, httpcore.jar, itext.jar, iText-2.1.7.jar, iText-rtf-2.1.7.jar, janino.jar, jasperreports-3.5.1.jar, javassist.jar, jaxb-api-2.2.1.jar, jaxb-impl-2.2.1.1.jar, jaxb-xjc-2.2.1.1.jar, jaxrpc.jar, jaxrs-api.jar, jaxws-api.jar, jboss-cache.jar, jbosscache-core.jar, jboss-common-core.jar, jboss-deployers-client-spi.jar, jboss-deployers-core-spi.jar, jboss-el.jar, jboss-embedded-api.jar, jboss-jmx.jar, jboss-logging-spi.jar, jboss-seam.jar, jboss-seam-debug.jar, jboss-seam-excel.jar, jboss-seam-flex.jar, jboss-seam-ioc.jar, jboss-seam-jul.jar, jboss-seam-mail.jar, jboss-seam-pdf.jar, jboss-seam-remoting.jar, jboss-seam-resteasy.jar, jboss-seam-rss.jar, jboss-seam-ui.jar, jboss-seam-wicket.jar, jboss-seam-wicket-ant.jar, jboss-system.jar, jboss-vfs.jar, jbpm-jpdl.jar, jcip-annotations.jar, jcl-over-slf4j.jar, jcommon-1.0.16.jar, jettison.jar, jfreechart-1.0.13.jar, jgroups.jar, jms.jar, joda-time.jar, jsf_core.tld, jsf-api.jar, jsf-facelets.jar, jsf-impl.jar, jsp-api.jar, jsr181-api.jar, jsr250-api.jar, jta.jar, jta-1.1.jar, junit.jar, jxl.jar, laguna-3.3.3.Final.jar, log4j-1.2.14.jar, lucene-core.jar, mail.jar, meldware-mailapi.jar, meldware-mailjmx.jar, metawidget.jar, metawidget-backend.jar, metawidget-frontend.jar, mvel2.jar, neethi-3.0.1.jar, openid4java.jar, openxri-client.jar, openxri-syntax.jar, persistence-api.jar, poi-3.2-FINAL-20081019.jar, portlet.jar, portlet-api.jar, psadvanced-1.25.jar, pscommons-1.57.jar, pshibernate-1.35.jar, psjsf-1.23.jar, quartz.jar, resteasy-atom-provider.jar, resteasy-jaxb-provider.jar, resteasy-jaxrs.jar, resteasy-jettison-provider.jar, richfaces-api-3.3.3.Final.jar, richfaces-impl-3.3.3.Final.jar, richfaces-impl-jsf2-3.3.3.Final.jar, richfaces-ui-3.3.3.Final.jar, saaj.jar, saaj-api-1.3.jar, saaj-impl-1.3.2.jar, servlet-api.jar, slf4j-api-1.5.8.jar, slf4j-log4j12.jar, spring.jar, spring-beans-3.0.5.RELEASE.jar, spring-context-3.0.5.RELEASE.jar, spring-core-3.0.5.RELEASE.jar, spring-expression-3.0.5.RELEASE.jar, spring-web-3.0.5.RELEASE.jar, stax2-api-3.1.1.jar, stax-api.jar, testng-jdk15.jar, themes-3.3.3.Final.jar, urlrewrite-3.2.0.jar, urlrewritefilter.jar, velocity-1.7.jar, web-facesconfig_1_0.dtd, web-facesconfig_1_1.dtd, woodstox-core-asl-4.1.1.jar, wsdl4j.jar, wsdl4j-1.6.2.jar, xml-apis.jar, xml-resolver-1.2.jar, XMLSchema.dtd, xmlschema-core-2.0.jar, xpp3_min.jar, xstream.jar, yarfraw.jar




      1. Installing CXF



      Download CXF and extract somewere. Copy required jars from CXF/lib to your WEB-INF/lib directory. In CXF's lib directory there is a file WHICH_JARS - it can help you choose appropiate jars. I copied the following:


      - cxf.jar
      - commons-logging.jar
      - neethi.jar
      - XmlSchema.jar
      - woodstox-core-asl.jar  [6] or another StAX implementation
      - stax2-api-3.0.1.jar [6] for woodstox above
      - wsdl4j.jar
      - xml-resolver.jar 
      - jaxb-xjc.jar
      - velocity.jar
      - commons-collections.jar
      - commons-lang.jar
      - cxf-xjc*.jar
      - geronimo-ws-metadata.jar [6]
      - geronimo-jaxws_2.2_spec-1.0.jar (Or the Sun equivalent) [6]
      - saaj-api.jar [6]
      - saaj-impl.jar [6]
      - asm.jar
      - aopalliance.jar
      - spring-beans.jar
      - spring-context.jar
      - spring-core.jar
      - spring.web.jar
      - FastInfoset.jar



      2. Configure CXF



      How to configure CXF in tomcat


      2.1. Web service configuration file




      You need to add to your web.xml spring configuration loading listener so the jaxws configuration file could load. In this file there will be configuration of your web service endpoint. Location of the file may be customized - for test purposes I throw it into classpath.


      <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:/jaxws-config.xml</param-value>
      </context-param>
      
      <listener>
        <listener-class>
          org.springframework.web.context.ContextLoaderListener
        </listener-class>
      </listener
      



      Empty (no endpoints configured) jaxws-config.xml whould look like this:


      <beans xmlns="http://www.springframework.org/schema/beans"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xmlns:jaxws="http://cxf.apache.org/jaxws"
            xmlns:seam="http://jboss.com/products/seam/spring-seam"
            xsi:schemaLocation="http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans.xsd
      http://cxf.apache.org/jaxws
      http://cxf.apache.org/schemas/jaxws.xsd
      http://jboss.com/products/seam/spring-seam
      http://jboss.com/products/seam/spring-seam-2.2.xsd">
      
        <import resource="classpath:META-INF/cxf/cxf.xml" />
        <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml"/>
        <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
        
        
      </beans> 
      



      It is basicly a spring beans configuration file. We add a jaxws extention for web service config and spring-seam for integrating seam components with spring beans.


      2.2 CXF servlet



      You also need to configure a CXF servlet, which will provide web services. Add the following code to web.xml file:


      <servlet>
        <servlet-name>CXFServlet</servlet-name>
          <servlet-class>
            org.apache.cxf.transport.servlet.CXFServlet
        </servlet-class>
      </servlet>
        
      <servlet-mapping>
            <servlet-name>CXFServlet</servlet-name>
        <url-pattern>/services/*</url-pattern>
      </servlet-mapping> 
      



      The url-pattern may be customized - basicly it is a prefix for en endpoint address.



      3. Defining service



      How to create and configure web service


      3.1. Creating java classes



      The following are a service class and interface. To create a client-side classes, you can generate wsdl (using cxf tools) and then create client-side classes from wsdl file using eclipse build-in function)


      import javax.jws.WebParam;
      import javax.jws.WebService;
      
      @WebService
      public interface TestService {     
           public String sayHallo(@WebParam(name="text") String name);
      }
      



      import java.util.Date;
      
      import javax.jws.WebMethod;
      import javax.jws.WebService;
      import javax.jws.soap.SOAPBinding;
      import javax.persistence.EntityManager;
      
      import org.jboss.seam.ScopeType;
      import org.jboss.seam.annotations.In;
      import org.jboss.seam.annotations.Name;
      import org.jboss.seam.annotations.Scope;
      
      @Name("testWebService")
      @Scope(ScopeType.STATELESS)
      @WebService(name = "TestService", serviceName = "TestSerivce",endpointInterface = "TestService")
      @SOAPBinding(style=SOAPBinding.Style.RPC)
      public class TestServiceImpl implements TestService{
      
           @In EntityManager entityManager;
           @In(create=true) Date currentDate;
           
           @WebMethod
           public String sayHallo(String name) {
                return "Hallo "+ name + "! Current server date is "+currentDate+" and entityManager="+entityManager;
           }
           
      }
      



      You can see, that the service implementor is a seam component. This gives you access to any seam ioc abilities.


      3.2 Configure endpoint



      Now you need to configure endpoint in your jaxws-config.xml file. It shoud look like this:


      
      <beans xmlns="http://www.springframework.org/schema/beans"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xmlns:jaxws="http://cxf.apache.org/jaxws"
            xmlns:seam="http://jboss.com/products/seam/spring-seam"
            xsi:schemaLocation="http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans.xsd
      http://cxf.apache.org/jaxws
      http://cxf.apache.org/schemas/jaxws.xsd
      http://jboss.com/products/seam/spring-seam
      http://jboss.com/products/seam/spring-seam-2.2.xsd">
      
        <import resource="classpath:META-INF/cxf/cxf.xml" />
        <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml"/>
        <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
        
        <jaxws:endpoint id="testServiceEndpoint"
                        implementor="#testWebServiceSpring"
                        address="/testService">
                        <jaxws:handlers>
                                <bean id="seamHandler" class="org.jboss.seam.webservice.SOAPRequestHandler"/>
                              </jaxws:handlers>
        </jaxws:endpoint>
        
        <seam:instance name="testWebService" id="testWebServiceSpring" proxy="true"/>
      </beans> 
      
      



      Our service will be availible from http://localhost:8080/yourApplicationName/services/testService path, assuming that you're deploying on localhost:8080 and configured CXF servlet under /services path.


      There are 2 important config points in our file. First is that we use seam handler.


      
      <jaxws:handlers>
        <bean id="seamHandler" class="org.jboss.seam.webservice.SOAPRequestHandler"/>
      </jaxws:handlers>
      
      



      It gives you ability to access seam context during web service request processing. There is another way to access seam context - you can use seam context filter:


      (in web.xml)
      <filter>
        <filter-name>Seam Servlet Filter</filter-name>
        <filter-class>org.jboss.seam.web.ContextFilter</filter-class>
      </filter> 
      
      <filter-mapping>
        <filter-name>Seam Servlet Filter</filter-name>
        <url-pattern>/services/*</url-pattern>
      </filter-mapping>
      
      
      or alternatively: 
      
      
      (in components.xml)
      <web:context-filter url-pattern="/services/*" />
      
      



      The important thing is to remember never to use both Seam SOAP Handler and Seam Context Filter - it will crush your service during request processing. I choosed SOAP Handler.


      Another interesting point is line integrating seam and spring. CXF uses spring beans. If we want to use seam component, we need to integrate it with spring using line:


      <seam:instance name="testWebService" id="testWebServiceSpring" proxy="true"/>
      
      


      Remember to put '#' in front of bean name in enpoints imeplementor property.


      Why do we want to use seam component? It is beacause we want cool seam interceptors like bijection interceptor, which processes @In annotations. Alternatively you can specify configuration as follwing:


      <jaxws:endpoint id="testServiceEndpoint"
                        implementor="org.test.ServiceClassName"
                        address="/testService">
                        <jaxws:handlers>
                                <bean id="seamHandler" class="org.jboss.seam.webservice.SOAPRequestHandler"/>
                              </jaxws:handlers>
        </jaxws:endpoint>
      
      

       
      This way you stil can access seam components through Component.getInstance, but the service object is not seam component - @In annotations wont work.


      Hope this little tutorial help someone. Any comments aprieciated.