In addition to the starter application, the JiBX/WS distribution includes the following examples:

SOAP Hello World

Demonstrates basic SOAP usage

POX Hello World

Demonstrates basic POX usage

Spring Hello World

Demonstrates basic Spring configuration of JiBX/WS

SOAP Headers

Demonstrates SOAP headers

SOAP Fault Trace

Demonstrates SOAP faults including stack trace details

SOAP Fault Custom

Demonstrates SOAP faults including custom actor and details elements

Custom Exception Handler

Demonstrates the use of a custom exception handler to return an error class instead of a SOAP fault

HTTP Servlet Interceptor

Demonstrates the use of interceptors to log the raw request and response messages

Seismic

Demonstrates a single application running SOAP or POX, over HTTP or TCP, and using either a text or XBIS encoding. In addition the application demonstrates WSDL publishing. This example allows the payload size to be configured, making it useful for performance benchmarking.

Building and running the examples

The examples folder contains a "super" build.xml file that sequentially invokes the build files of all of the examples. For example, invoking "ant build deploy-tomcat run" from the examples folder will build all of the examples, then deploy them all, then run them all. The Spring examples will be skipped if the Spring dependencies are not in the spring-lib folder.

Each example application has a separate Ant build file (eg. examples/hello/build/soap/build.xml under the JiBX/WS root directory). The "build-client" Ant target builds the client side of the application, "build-server" the server side (creating a war file in the build folder of the relevant example), and "run" executes the actual client application. The default target is "build", which invokes "build-server" followed by "build-client". In order to run the client successfully you'll need to have first deployed the application war file to a server. If your server is Tomcat, you can use the "deploy-tomcat" target to copy the war file to Tomcat's webapps folder, assuming that the CATALINA_HOME environment variable has been set to Tomcat's root folder.

Use the "run" target to run the examples. The examples assume they are running on port 8080. You can change the host and/or port for all examples by modifying the http.target.host and http.target.port properties in examples/build.properties.

To reduce duplication the example build files all import the common.xml build file from the examples folder. To determine all of the targets available for each example's build file, run "ant -p" against the build file.

SOAP Hello World Application

This example demonstrates basic SOAP usage. The client sends a request containing the name of a "greetee" and the server responds with a welcome greeting to the greetee.

The source for this application is under examples/hello/build/src. The build file is examples/hello/build/soap/build.xml.

The mapping of the Greetee and Welcome Java classes to and from the request and response XML is in hello-binding.xml. The HelloClient class looks up this binding in the BindingDirectory and constructs a SoapClient using this binding. On invoking Client.call(), the JiBX/WS framework then marshals the request object to the body of the SOAP request using the specified binding, makes the SOAP request, waits for the SOAP response, unmarshals the SOAP response body to a Java object and returns this object.

On the server side, the web.xml file defines the JiBX/WS servlet and references the service definition file (welcome-service.xml):

<web-app>
  
  <servlet>
    <servlet-name>jibx-ws-hello-soap</servlet-name>
    <servlet-class>org.jibx.ws.http.servlet.WsServlet</servlet-class>
    <init-param>
      <param-name>welcome-service</param-name>
      <param-value>welcome-service.xml</param-value>
    </init-param>
  </servlet>
  
  <servlet-mapping>
    <servlet-name>jibx-ws-hello-soap</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
 
</web-app>

The service definition file specifies the name of the service class and the method to be invoked:

<service name="jibxws.example.hello">
  <service-class>org.jibx.ws.example.hello.soap.server.HelloServer</service-class>
  <operation method="welcomeService"/>
</service>

In this example, the service implementation is a simple method:

    public Welcome welcomeService(Greetee greeetee) {
        return new Welcome("Hello " + greeetee.getName() + "!");
    }

On the server side, the JiBX/WS framework determines which binding to use based on the type of the parameters to the service operation. On invocation, the framework unmarshals the body of the SOAP request to a Java object, determines which service method to call based on the type of the unmarshalled request object, calls the service method and marshals the response object as the body of the SOAP response.

POX Hello World Application

This example is almost identical to the SOAP Hello World example, except that it sends the payload using POX (Plain Old XML) rather than as the body of SOAP messages.

HelloClient creates a PoxClient rather than a SoapClient. On the server side, the service definition file welcome-service.xml contains the extra attribute protocol="POX".

Spring Hello World Application

This example configures the JiBX/WS server and client using Spring.

The source for this application is under examples/spring/build/src. The build file is examples/spring/build/soap/build.xml.

The org/jibx/ws/example/spring/hello/soap/server/ source directory contains the server configuration. The web.xml file configures the servlet to use the WsSpringServlet class. WsSpringServlet is an extension of Spring's FrameworkServlet class, customized to work with JiBX/WS. By default, the Spring application context will be loaded from an XML file whose name is based on the servlet-name. In this case, since the servlet-name is jibx-ws-spring-hello-soap, the context is loaded from the file jibx-ws-spring-hello-soap-servlet.xml.

The Spring configuration file contains:

  <bean id="helloService" class="org.jibx.ws.example.spring.hello.soap.server.HelloServer">
    <property name="greeting" value="Hola"/>
  </bean>
  
  <bean id="serviceDefinition" class="org.jibx.ws.server.ServiceDefinition" init-method="init">
    <property name="serviceObject" ref="helloService" /> 
    <property name="operationDefinitions">
      <list>
        <bean class="org.jibx.ws.server.OperationDefinition" >
          <property name="methodName" value="welcomeService" />
        </bean>
      </list>
    </property>
  </bean>
  
  <bean id="serviceMapper" class="org.jibx.ws.http.servlet.SingleServiceMapper"> 
    <property name="serviceDefinition" ref="serviceDefinition"/>
  </bean>
  

WsSpringServlet depends on a serviceMapper bean. In this case, the application is only exposing a single web service, and it uses the SingleServiceMapper class. The serviceDefinition bean defines the web service as exposing a single operation based on the welcomeService method of the helloService bean.

[Note: It is planned to simplify the Spring configuration in a future release using a custom namespace.]

By default, Spring beans are configured using Singleton scope. Using the configuration above, a single instance of the helloService bean is shared by all the servlet instances handling requests for our web service. The output from the Spring example confirms that the same instance is being used for each request:

     [java] Hola World from org.jibx.ws.example.spring.hello.soap.server.HelloServer@25927275 !
     [java] Hola World from org.jibx.ws.example.spring.hello.soap.server.HelloServer@25927275 !
     [java] Hola World from org.jibx.ws.example.spring.hello.soap.server.HelloServer@25927275 !

Spring Request Scope

Spring-based applications will normally be written in a thread-safe manner where Singleton scope is appropriate. However, if you require a different object per request, this can be achieved using Spring's Request scope.

The org/jibx/ws/example/spring/request/scope/server directory contains the server configuration required to to use Spring's request scope. The web.xml file contains an additional listener-class:

  <listener>
    <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
  </listener>

, and the Spring configuration file contains an additional scope attribute, and an aop:scoped-proxy element to inject a Spring AOP proxy object.

  <bean id="helloService" class="org.jibx.ws.example.spring.hello.soap.server.HelloServer" scope="request">
    <property name="greeting" value="Namaste"/>
    <aop:scoped-proxy />    
  </bean>

The output from this example shows that a different instance is being used per request:

     [java] Namaste World from org.jibx.ws.example.spring.hello.soap.server.HelloServer@635c80a4 !
     [java] Namaste World from org.jibx.ws.example.spring.hello.soap.server.HelloServer@55641ee0 !
     [java] Namaste World from org.jibx.ws.example.spring.hello.soap.server.HelloServer@20272fec !

SOAP Headers Application

This example, in the examples/soap-headers directory, builds on the SOAP Hello World example, by adding a SOAP header to the request that includes the locale of the user. The server responds with a locale-specific greeting. The SOAP response includes a header with a (hard-coded) QOS measure.

The example includes an additional binding file example-binding.xml which includes the bindings for Locale and QOS. (These additional bindings could equally have been included in the existing binding file hello-binding.xml).

The client application calls client.addOutHeader(new Locale("fr")); to add an outbound SOAP header containing the french Locale. In order to read the response header, the client includes the following lines:

        UnmarshallingInHandler headerHandler = new UnmarshallingInHandler(QOS.class);
        client.addInHeaderHandler(headerHandler);
        ...
        System.out.println("QOS: " + headerHandler.getPayload());

On the server side, the service definition file includes the following two additional handlers:

  <handler-class class="org.jibx.ws.io.handler.ContextAttributeUnmarshallingInHandler">
    <constructor-arg value="org.jibx.ws.example.headers.common.Locale"/>
    <constructor-arg value="example.locale"/>
  </handler-class>
  <handler-class class="org.jibx.ws.io.handler.ContextAttributeMarshallingOutHandler">
    <constructor-arg value="org.jibx.ws.example.headers.common.QOS"/>
    <constructor-arg value="comm.qos"/>
  </handler-class>

The first handler is of type ContextAttributeUnmarshallingInHandler which unmarshalls the SOAP header and stores the resulting object in the inbound message context. In this case, the Locale object is stored in the example.locale attribute. The HelloServer.welcomeService() method reads the the Locale object from this attribute with the call:

        Locale locale = (Locale) inCtx.getAttribute("example.locale");

To set the outbound header object, the welcomeService method sets the attribute comm.qos on the outbound message context. The second handler above is configured to read from comm.qos and marshal the QOS object in an outbound SOAP header.

SOAP Fault with Stack Trace Details Application

This example, in the examples/soap-fault-trace directory, builds on the SOAP Hello World example, by throwing an exception if the greetee name doesn't start with the letter 'Z'. The JiBX/WS framework catches the exception and returns a SOAP fault. By default the stack trace is not included in the response. This example adds the following element to the service definition file service-mapping.xml to request the stack trace to be included:

    <fault include-stack-trace="true"/>

To configure the client application to read the Exception details of the SOAP Fault, the following line is added:

    client.addInFaultDetailsHandler(new ExceptionReader());

SOAP Fault with Custom Fault Actor and Details Application

This example, in the examples/soap-fault-custom directory, builds on the SOAP Hello World example, by returning a fault if the greetee name doesn't start with the letter 'Z'. In this example, a custom SOAP Fault is returned including an actor and custom SOAP Fault details.

On the server side, the service throws a SoapFaultException containing a SoapFault object which includes the actor and adds a fault details writer:

    SoapFault fault = new SoapFault(SoapFault.FAULT_CODE_SERVER, "ZorroFault in welcomeService", 
        "http://example.ws.jibx.org/someactor");
        
    fault.addDetailWriter(new PayloadMarshaller(zorroFault));
    
    throw new SoapFaultException(fault);

The example-binding.xml file contains the binding of the ZorroFault class to XML. The JiBX/WS framework catches the SoapFaultException and marshals the custom SoapFault.

No extra configuration is required on the client side, since the fault detail element is defined in the binding file that was passed to the SoapClient constructor. The client catches the SoapFaultException and prints out the name and message from the custom fault details element.

Custom Exception Handler Example Application

This example, in the examples/custom-exception-handler directory, demonstrates the use of a custom service-exception-handler-class to override the default server side exception handling. Custom exception handlers are not normally needed for SOAP services, since the built-in SOAP Fault handler is sufficient. However for POX applications, there is no standard fault mechanism and it will often be necessary to override the default exception handler provided with JiBX/WS.

On the server side, the ExceptionHandler class implements the ServiceExceptionHandler interface. On exception, it creates a new ServiceError object and sends an outbound message using the marshaled form of this object as the body.

The client code checks the type of the unmarshalled body object to determine whether it is a ServiceError.

HTTP Servlet Interceptor Example Application

This example, in the examples/http-servlet-interceptor directory, demonstrates the use of input and output stream interceptors to log the raw request and response messages, both on the client and server side.

Note that transport interceptors are limited to working with HTTP, and are only useful in the limited cases where you need access to the raw messages. For most cases, XML stream interceptors are preferred. These will be implemented in a future release.

Seismic Example Application

This example, in the examples/seismic directory, demonstrates many of the JiBX/WS features in a single application. The application can be run using SOAP or POX, over HTTP or TCP, and using either a text or XBIS encoding.

The example runs queries against an in-memory database on the server to retrieve information about moderate to large earthquakes recorded around the world during a particular time span. The client generates a pseudo-random sequence of queries based on command line arguments, sending each query to the server which then responds with the set of matching quakes.

Here's the quake-service.xml service definition file referenced by the web.xml:

<service name="quake">
  <service-class>com.sosnoski.seismic.server.QuakeBase</service-class>
  <operation method="process"/>
  <wsdl file="/SeismicService.wsdl" transformLocation="true"/>
</service>

These files configure a single web service at the access path http://server:port/webapp/quake-service, where server:port is the name and port number for the servlet engine (such as localhost:8080 for the standard Tomcat configuration) and webapp is the name of the web application (normally the name of the .war file deployed to the server).

The <wsdl file="/SeismicService.wsdl"> definition causes JiBX/WS to return a WSDL definition on an HTTP GET request. In this example, a browser query to http://localhost:8080/jibx-ws-seismic/soap/quake-service?wsdl returns the contents of the /SeismicService.wsdl file (relative to the WEB-INF/classes folder of the jibx-ws-seismic.war file). The service location in the WSDL is transformed based on the incoming WSDL request URL.

The /examples/seismic/run.sh script gives another way of running the client application, as is used for performance testing comparisons with other frameworks.