You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 19 Next »

Setting up your web.xml

To set up CXF to use a Servlet you'll need to add the CXFServlet to your web.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>
  </servlet>

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

To create services that use this transport you can either use the CXF APIs (for instance, JAX-WS) or you can create an XML file which registers services for you.

Publishing an endpoint with XML

CXF uses Spring to provide XML configuration of services. This means that first we'll want to load Spring via a Servlet listener and tell it where oure XML configuration file is:

<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>

NOTE: this is in the process of being simplified so will not have to add the ContextLoaderListener in future releases.

The next step is to actually write the configuration file:

<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:jaxws="http://cxf.apache.org/jaxws"
      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">

  <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="greeter"
                  implementor="org.apache.hello_world_soap_http.GreeterImpl"
                  address="/Greeter1"/>
</beans>

Here we're creating a JAX-WS endpoint based on our implementation class, GreeterImpl.

NOTE: We're publishing this class at the address "http://localhost/mycontext/services/Greeter1", but we set the jaxws:endpoint@address with a related path "/Greeter1". Since Servlets are not aware of their HTTP address, the Servlet will listen for requests on all available hosts/ports that it has been set up to listen on by its container.

Publishing an endpoint with the API

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 it's HTTP Transport. Simply publish with the related path "Greeter" and your service should appear at the address you specify:

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());

The one thing you must ensure is that your CXFServlet is set up to listen on that path. Otherwise the CXFServlet will never receive the requests.

NOTE:

Endpoint.publish(...) is a JAX-WS API for publishing JAX-WS endpoints. Thus, it would require the JAX-WS module and API's to be present. If you are not using JAX-WS or want more control over the published endpoint properties, you should replace that call with the proper calls to the appropriate ServerFactory.

Since CXFServlet know nothing about the web container listen port and the application context path, you need to specify the relate path instead of full http address.

Using the servlet transport without Spring

Some user who don't want to touch any Spring stuff could also publish the endpoint with CXF servlet transport. First you should extends the CXFNonSpringServlet and override the method loadBus which below codes:

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());               
    }

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

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);
            }
        }

Accessing the MessageContext and/or HTTP Request and Response

Sometimes you'll want to access more specific message details in your service implementation. One example might be accessing the actual request or response object itself. This can be done using the WebServiceContext object.

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

@Resource
private WebServiceContext context;

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

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);

Of course, it is always a good idea to program defensively if using transport-specific entities like the HttpServletRequest and HttpServletResponse. If the transport were changed (for instance to the JMS transport), then these values would likely be null.

  • No labels