This Confluence has been LDAP enabled, if you are an ASF Committer, please use your LDAP Credentials to login. Any problems file an INFRA jira ticket please.

Child pages
  • Servlet Transport

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Next, you'll need to add CXFServlet to your web.xml:

Code Block
xml
xml

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
      classpath:com/acme/ws/services.xml
    </param-value>
  </context-param>

  <listener>
    <listener-class>
      org.springframework.web.context.ContextLoaderListener
    </listener-class>
  </listener>

  <servlet>
    <servlet-name>CXFServlet</servlet-name>
    <display-name>CXF Servlet</display-name>
    <servlet-class>
       org.apache.cxf.transport.servlet.CXFServlet
    </servlet-class>
    <load-on-startup>1</load-on-startup> 
  </servlet>

  <servlet-mapping>
    <servlet-name>CXFServlet</servlet-name>
    <url-pattern>/services/*</url-pattern>
  </servlet-mapping>

</web-app>

Alternatively, you can point to the configuration file using a CXFServlet init parameter :

Code Block
xml
xml

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>

  <servlet>
    <servlet-name>CXFServlet</servlet-name>
    <display-name>CXF Servlet</display-name>
    <servlet-class>
        org.apache.cxf.transport.servlet.CXFServlet
    </servlet-class>
    <init-param>
      <param-name>config-location</param-name>
      <param-value>/WEB-INF/beans.xml</param-value>    
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>CXFServlet</servlet-name>
    <url-pattern>/services/*</url-pattern>
  </servlet-mapping>
  
</web-app>

The next step is to actually write the configuration file:

Code Block
xml
xml

<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:jaxrs="http://cxf.apache.org/jaxrs"
      xsi:schemaLocation="
         http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
         http://cxf.apache.org/jaxws
         http://cxf.apache.org/schemas/jaxws.xsd
         http://cxf.apache.org/jaxrs
         http://cxf.apache.org/schemas/jaxrs.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-extension-jaxrs-binding.xml"/>
  <import resource="classpath:META-INF/cxf/cxf-servlet.xml"/>

  <jaxws:endpoint id="greeter"
      implementor="org.apache.hello_soap_http.GreeterImpl"
      address="/Greeter1"/>

  <jaxrs:server id="greeterRest"
      serviceClass="org.apache.hello_soap_http.GreeterImpl"
      address="/GreeterRest"/> 

</beans>

...

NOTE: We're publishing endpoints "http://localhost/mycontext/services/Greeter1" and "http://localhost/mycontext/services/GreeterRest", but we set jaxws:endpoint/@address and jaxrs:server/@address to relative values such as "/Greeter1" "/GreeterRest".

Disabling the Services Page

By default, Apache CXF creates a /services page containing a listing of the available endpoints. To disable this listing, configure the Servlet as follows:

Code Block
languagejava
titleDisable Services Listing
<servlet>
    ....
    <init-param>
        <param-name>hide-service-list-page</param-name>
        <param-value>true</param-value>
    </init-param> 
</servlet>

 

Support for Asynchronous Requests

Enable an 'async-supported' servlet property if you work with Servlet3 API containers and need to support asynchronous requests:

Code Block
xml
xml

<servlet>
    <servlet-name>CXFServlet</servlet-name>
    <display-name>CXF Servlet</display-name>
    <servlet-class>
       org.apache.cxf.transport.servlet.CXFServlet
    </servlet-class>

    <!-- Enable asynchronous requests -->
 
    <async-supported>true</async-supported>

    <load-on-startup>1</load-on-startup> 
</servlet>

...

The "http://localhost:9080/the/bookstore1/books/html/123" request URI will initially be matched by the CXFServlet given that it has a more specific URI pattern than the RedirectCXFServlet. After a current URI has reached a jaxrs:server endpoint, the response will be redirected by the JAXRS RequestDispatcherProvider to a "/book.html" address, see "dispatchProvider1" bean here.

Next, the request URI "/book.html" will be handled by RedirectCXFServlet. Note that a uri pattern can be a regular expression. This servlet redirects the request further to a RequestDispatcher capable of handling a "/static/book.html".

...

Option1. Delegating to Default Servlet

Code Block
xml
xml

<servlet>
   <servlet-name>CXFServlet</servlet-name>
   <display-name>CXF Servlet</display-name>
   <servlet-class>
      org.apache.cxf.transport.servlet.CXFServlet
   </servlet-class>
   <init-param>
      <param-name>redirects-list</param-name>
      <param-value>
         /
         /index.html
      </param-value>
   </init-param>
   <init-param>
       <param-name>redirect-attributes</param-name>
       <param-value>
         javax.servlet.include.request_uri
       </param-value>
   </init-param>
   <init-param>
       <param-name>redirect-servlet-name</param-name>
       <param-value>default</param-value>
   </init-param>
   <load-on-startup>1</load-on-startup>
</servlet>
 
<servlet-mapping>
   <servlet-name>CXFServlet</servlet-name>
   <url-pattern>/*</url-pattern>
</servlet-mapping>

<welcome-file-list>
   <welcome-file>index.html</welcome-file>
</welcome-file-list>

...

Option2. Using CXFServlet itself to read index.html

Code Block
xml
xml

<servlet>
   <servlet-name>CXFServlet</servlet-name>
   <display-name>CXF Servlet</display-name>
   <servlet-class>
      org.apache.cxf.transport.servlet.CXFServlet
   </servlet-class>
   <init-param>
      <param-name>static-welcome-file</param-name>
      <param-value>/index.html</param-value>
   </init-param> 
   <init-param>
      <param-name>static-resources-list</param-name>
      <param-value>/index.html</param-value>
   </init-param> 
   <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
   <servlet-name>CXFServlet</servlet-name>
   <url-pattern>/*</url-pattern>
</servlet-mapping>

...

Once your Servlet is registered in your web.xml, you should set the default bus with CXFServlet's bus to make sure that CXF uses it as its HTTP Transport. Simply publish with the related path "Greeter" and your service should appear at the address you specify:

Code Block
java
java

import javax.xml.ws.Endpoint;
import org.apache.cxf.Bus;
import org.apache.cxf.BusFactory;
import org.apache.cxf.transport.servlet.CXFServlet;
.....
// cxf is the instance of the CXFServlet, you could also get 
// this instance by extending the CXFServlet
Bus bus = cxf.getBus();
BusFactory.setDefaultBus(bus); 
Endpoint.publish("/Greeter", new GreeterImpl());

...

A user who doesn't want to touch any Spring stuff could also publish the endpoint with CXF servlet transport. First you should extend the CXFNonSpringServlet and then override the method loadBus, e.g.:

Code Block
java
java

import javax.xml.ws.Endpoint;
...  
  
    @Override
    public void loadBus(ServletConfig servletConfig) throws ServletException {
        super.loadBus(servletConfig);        
        
        // You could add the endpoint publish codes here
        Bus bus = cxf.getBus();
        BusFactory.setDefaultBus(bus); 
        Endpoint.publish("/Greeter", new GreeterImpl());
        
        // You can als use the simple frontend API to do this
        ServerFactoryBean factroy = new ServerFactoryBean();
        factory.setBus(bus);
        factory.setServiceClass(GreeterImpl.class);
        factory.setAddress("/Greeter");
        factory.create();              
    }

If you are using the Jetty as the embedded servlet engine, you could publish endpoint like this:

Code Block
java
java

import javax.xml.ws.Endpoint;
...

        // Setup the system properties to use the CXFBusFactory not the SpringBusFactory
        String busFactory = 
            System.getProperty(BusFactory.BUS_FACTORY_PROPERTY_NAME);
        System.setProperty(BusFactory.BUS_FACTORY_PROPERTY_NAME, 
            "org.apache.cxf.bus.CXFBusFactory");
        try {
            // Start up the jetty embedded server
            httpServer = new Server(9000);
            ContextHandlerCollection contexts = new ContextHandlerCollection();
            httpServer.setHandler(contexts);
            
            Context root = new Context(contexts, "/", Context.SESSIONS);
            
            CXFNonSpringServlet cxf = new CXFNonSpringServlet();
            ServletHolder servlet = new ServletHolder(cxf);
            servlet.setName("soap");
            servlet.setForcedPath("soap");
            root.addServlet(servlet, "/soap/*");
            
            httpServer.start();
            
            Bus bus = cxf.getBus();
            setBus(bus);
            BusFactory.setDefaultBus(bus);
            GreeterImpl impl = new GreeterImpl();
            Endpoint.publish("/Greeter", impl);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            // clean up the system properties
            if (busFactory != null) {
                System.setProperty(BusFactory.BUS_FACTORY_PROPERTY_NAME, 
                   busFactory);
            } else {
                System.clearProperty(BusFactory.BUS_FACTORY_PROPERTY_NAME);
            }
        }

...

First, declare a private field for the WebServiceContext in your service implementation, and annotate it as a resource:

Code Block
java
java

@Resource
private WebServiceContext context;

Then, within your implementing methods, you can access the MessageContext, HttpServletRequest, and HttpServletResponse as follows:

Code Block
java
java

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.ws.handler.MessageContext;
import org.apache.cxf.transport.http.AbstractHTTPDestination;
...

MessageContext ctx = context.getMessageContext();
HttpServletRequest request = (HttpServletRequest) 
    ctx.get(AbstractHTTPDestination.HTTP_REQUEST);
HttpServletResponse response = (HttpServletResponse) 
    ctx.get(AbstractHTTPDestination.HTTP_RESPONSE);

...