Web Services SEAM + CXF + Tomcat (no JBoss Embedded)
jwisnie1 Aug 31, 2011 10:58 AMWeb 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.