Version 7.1
Copyright © 2012 Red Hat, Inc. and/or its affiliates.
Updated: 08 Jan 2014
Table of Contents
JAXBContext ObjectList of Figures
List of Tables
@WebService Properties@SOAPBinding Properties@WebMethod Properties@RequestWrapper Properties@ResponseWrapper Properties@WebFault Properties@WebParam Properties@WebResult PropertiesWebServiceExceptioncreateDispatch()@WebServiceProvider PropertiesList of Examples
@WebService AnnotationService create() MethodsService ObjectaddPort() MethodService ObjectgetPort() MethodServiceContractResolver InterfacecheckWidgets()checkWidgets()placeWidgetOrder()javax.xml.ws.AsyncHandler InterfacecreateDispatch() MethodDispatch ObjectDispatch.invoke() MethodDispatch ObjectDispatch.invokeAsync() Method for PollingDispatch.invokeAsync() Method Using a CallbackDispatch.invokeOneWay() MethodDispatch ObjectProvider Implementation Uses Message ModeProvider Implementation Uses Payload ModeProvider<SOAPMessage> ImplementationProvider<DOMSource> ImplementationMessageContext.setScope() MethodMessageContext.get() MethodMessageContext.put() MethodgetRequestContext() MethodgetResponseContext() MethodLogicalHandler SynopsisSOAPHandler SynopsisSOAPHander.getHeaders() MethodSOAPMessageContext.getHeaders() MethodThe JAX-WS APIs let you bypass the WSDL contract when developing services. You can start developing your services from a piece of Java code. The code might be a class, or classes, from a legacy application that is being upgraded. It can also be a class that is currently used as part of a non-distributed application and it implements features that you want to use in a distributed manner. You annotate the Java code and generate a WSDL document from the annotated code. If you do not want to work with WSDL at all, you can create the entire application without ever generating WSDL.
Table of Contents
There are many instances where you have Java code that already implements a set of functionality that you want to expose as part of a service oriented application. You may also simply want to avoid using WSDL to define your interface. Using JAX-WS annotations, you can add the information required to service enable a Java class. You can also create a Service Endpoint Interface (SEI) that can be used in place of a WSDL contract. If you want a WSDL contract, Fuse Services Framework provides tools to generate a contract from annotated Java code.
To create a service starting from Java you must do the following:
Create a Service Endpoint Interface (SEI) that defines the methods you want to expose as a service.
![]() | Tip |
|---|---|
You can work directly from a Java class, but working from an interface is the recommended approach. Interfaces are better suited for sharing with the developers who are responsible for developing the applications consuming your service. The interface is smaller and does not provide any of the service's implementation details. |
Add the required annotations to your code.
Generate the WSDL contract for your service.
![]() | Tip |
|---|---|
If you intend to use the SEI as the service's contract, it is not necessary to generate a WSDL contract. |
Publish the service as a service provider.
The service endpoint interface (SEI) is the piece of Java code that is shared between a service implementation and the consumers that make requests on that service. The SEI defines the methods implemented by the service and provides details about how the service will be exposed as an endpoint. When starting with a WSDL contract, the SEI is generated by the code generators. However, when starting from Java, it is the developer's responsibility to create the SEI.
There are two basic patterns for creating an SEI:
Green field development — In this pattern, you are developing a new service without any existing Java code or WSDL. It is best to start by creating the SEI. You can then distribute the SEI to any developers that are responsible for implementing the service providers and consumers that use the SEI.
![]() | Note |
|---|---|
The recommended way to do green field service development is to start by creating a WSDL contract that defines the service and its interfaces. See Part II: Starting from WSDL. |
Service enablement — In this pattern, you typically have an existing set of functionality that is implemented as a Java class, and you want to service enable it. This means that you must do two things:
Create an SEI that contains only the operations that are going to be exposed as part of the service.
Modify the existing Java class so that it implements the SEI.
![]() | Note |
|---|---|
Although you can add the JAX-WS annotations to a Java class, it is not recommended. |
The SEI is a standard Java interface. It defines a set of methods that a class implements. It can also define a number of member fields and constants to which the implementing class has access.
In the case of an SEI the methods defined are intended to be mapped to operations exposed by a service. The SEI corresponds to a
wsdl:portType element. The methods defined by the SEI correspond to wsdl:operation elements in the
wsdl:portType element.
![]() | Tip |
|---|---|
JAX-WS defines an annotation that allows you to specify methods that are not exposed as part of a service. However, the best practice is to leave those methods out of the SEI. |
Example 1.1 shows a simple SEI for a stock updating service.
Example 1.1. Simple SEI
package com.fusesource.demo;
public interface quoteReporter
{
public Quote getQuote(String ticker);
}Because the SEI is a standard Java interface, the class that implements it is a standard Java class. If you start with a Java class you must modify it to implement the interface. If you start with the SEI, the implementation class implements the SEI.
Example 1.2 shows a class for implementing the interface in Example 1.1.
Example 1.2. Simple Implementation Class
package com.fusesource.demo;
import java.util.*;
public class stockQuoteReporter implements quoteReporter
{
...
public Quote getQuote(String ticker)
{
Quote retVal = new Quote();
retVal.setID(ticker);
retVal.setVal(Board.check(ticker));[1]
Date retDate = new Date();
retVal.setTime(retDate.toString());
return(retVal);
}
}The JAX-WS annotations specify the metadata used to map the SEI to a fully specified service definition. Among the information provided in the annotations are the following:
The target namespace for the service.
The name of the class used to hold the request message
The name of the class used to hold the response message
If an operation is a one way operation
The binding style the service uses
The name of the class used for any custom exceptions
The namespaces under which the types used by the service are defined
![]() | Tip |
|---|---|
Most of the annotations have sensible defaults and it is not necessary to provide values for them. However, the more information you provide in the annotations, the better your service definition is specified. A well-specified service definition increases the likelihood that all parts of a distributed application will work together. |
In order to create a service from Java code you are only required to add one annotation to your code. You must add the
@WebService annotation on both the SEI and the implementation class.
The @WebService annotation is defined by the javax.jws.WebService interface and it is placed on
an interface or a class that is intended to be used as a service. @WebService has the properties described in
Table 1.1
Table 1.1. @WebService Properties
| Property | Description |
|---|---|
| name | Specifies the name of the service interface. This property is mapped to the name attribute of the
wsdl:portType element that defines the service's interface in a WSDL contract. The default is to append PortType to the
name of the implementation class.
[a]
|
| targetNamespace | Specifies the target namespace where the service is defined. If this property is not specified, the target namespace is derived from the package name. |
| serviceName | Specifies the name of the published service. This property is mapped to the name attribute of the
wsdl:service element that defines the published service. The default is to use the name of the service's implementation class.
[a]
|
| wsdlLocation | Specifies the URL where the service's WSDL contract is stored. This must be specified using a relative URL. The default is the URL where the service is deployed. |
| endpointInterface | Specifies the full name of the SEI that the implementation class implements. This property is only specified when the attribute is used on a service implementation class. |
| portName | Specifies the name of the endpoint at which the service is published. This property is mapped to the name attribute of the
wsdl:port element that specifies the endpoint details for a published service. The default is the append Port to the
name of the service's implementation class.[a] |
[a] When you generate WSDL from an SEI the interface's name is used in place of the implementation class' name. | |
![]() | Tip |
|---|---|
It is not necessary to provide values for any of the |
The SEI requires that you add the @WebService annotation. Because the SEI is the contract that defines the service, you should specify
as much detail as possible about the service in the @WebService annotation's properties.
Example 1.3 shows the interface defined in
Example 1.1 with the @WebService annotation.
Example 1.3. Interface with the @WebService Annotation
package com.fusesource.demo; import javax.jws.*; @WebService(name="quoteUpdater",targetNamespace="http:\\demos.fusesource.com",
serviceName="updateQuoteService",
wsdlLocation="http:\\demos.fusesource.com\quoteExampleService?wsdl",
portName="updateQuotePort")
public interface quoteReporter { public Quote getQuote(String ticker); }
The @WebService annotation in Example 1.3 does the following:
Specifies that the value of the | |
Specifies that the target namespace of the service is | |
Specifies that the value of the | |
Specifies that the service will publish its WSDL contract at | |
Specifies that the value of the |
In addition to annotating the SEI with the @WebService annotation, you also must annotate the service implementation class
with the @WebService annotation. When adding the annotation to the service implementation class you only need to specify the
endpointInterface property. As shown in Example 1.4 the property must
be set to the full name of the SEI.
Example 1.4. Annotated Service Implementation Class
package org.eric.demo;
import javax.jws.*;
@WebService(endpointInterface="com.fusesource.demo.quoteReporter")
public class stockQuoteReporter implements quoteReporter
{
public Quote getQuote(String ticker)
{
...
}
}While the @WebService annotation is sufficient for service enabling a Java interface or a Java class, it does
not fully describe how the service will be exposed as a service provider. The JAX-WS programming model uses a number of
optional annotations for adding details about your service, such as the binding it uses, to the Java code. You add these annotations to the service's
SEI.
![]() | Tip |
|---|---|
The more details you provide in the SEI the easier it is for developers to implement applications that can use the functionality it defines. It also makes the WSDL documents generated by the tools more specific. |
If you are using a SOAP binding for your service, you can use JAX-WS annotations to specify a number of the bindings properties. These properties correspond directly to the properties you can specify in a service's WSDL contract. Some of the settings, such as the parameter style, can restrict how you implement a method. These settings can also effect which annotations can be used when annotating method parameters.
The @SOAPBinding annotation is defined by the javax.jws.soap.SOAPBinding interface. It provides
details about the SOAP binding used by the service when it is deployed. If the @SOAPBinding annotation is not specified, a service is published
using a wrapped doc/literal SOAP binding.
You can put the @SOAPBinding annotation on the SEI and any of the SEI's methods. When it is used on a method, setting of the method's
@SOAPBinding annotation take precedence.
Table 1.2 shows the properties for the @SOAPBinding annotation.
Table 1.2. @SOAPBinding Properties
| Property | Values | Description |
|---|---|---|
| style |
| Specifies the style of the SOAP message. If RPC style is specified, each message part within the SOAP body is a parameter or return value
and appears inside a wrapper element within the soap:body element. The message parts within the wrapper element correspond to
operation parameters and must appear in the same order as the parameters in the operation. If DOCUMENT style is specified, the contents of
the SOAP body must be a valid XML document, but its form is not as tightly constrained. |
| use |
| Specifies how the data of the SOAP message is streamed. |
| parameterStyle [b] |
| Specifies how the method parameters, which correspond to message parts in a WSDL contract, are placed into the SOAP message body. If BARE is
specified, each parameter is placed into the message body as a child element of the message root. If WRAPPED is specified, all of the input parameters
are wrapped into a single element on a request message and all of the output parameters are wrapped into a single element in the response message. |
[a] [b] If you set the style to | ||
Document bare style is the most direct mapping between Java code and the resulting XML representation of the service. When using this style, the schema types are generated directly from the input and output parameters defined in the operation's parameter list.
You specify you want to use bare document\literal style by using the @SOAPBinding annotation with its style
property set to Style.DOCUMENT, and its parameterStyle property set to ParameterStyle.BARE.
To ensure that an operation does not violate the restrictions of using document style when using bare parameters, your operations must adhere to the following conditions:
The operation must have no more than one input or input/output parameter.
If the operation has a return type other than void, it must not have any output or input/output parameters.
If the operation has a return type of void, it must have no more than one output or input/output parameter.
![]() | Note |
|---|---|
Any parameters that are placed in the SOAP header using the |
Document wrapped style allows a more RPC like mapping between the Java code and the resulting XML representation of the service. When using this style, the parameters in the method's parameter list are wrapped into a single element by the binding. The disadvantage of this is that it introduces an extra-layer of indirection between the Java implementation and how the messages are placed on the wire.
To specify that you want to use wrapped document\literal style use the @SOAPBinding annotation with its
style property set to Style.DOCUMENT, and its parameterStyle property set to
ParameterStyle.WRAPPED.
You have some control over how the wrappers are generated by using the
@RequestWrapper annotation and
the @ResponseWrapper annotation.
Example 1.5 shows an SEI that uses document bare SOAP messages.
Example 1.5. Specifying a Document Bare SOAP Binding with the SOAP Binding Annotation
package org.eric.demo; import javax.jws.*; import javax.jws.soap.*; import javax.jws.soap.SOAPBinding.*; @WebService(name="quoteReporter") @SOAPBinding(parameterStyle=ParameterStyle.BARE) public interface quoteReporter { ... }
When the runtime maps your Java method definitions into XML operation definitions it provides details such as:
What the exchanged messages look like in XML
If the message can be optimized as a one way message
The namespaces where the messages are defined
The @WebMethod annotation is defined by the
javax.jws.WebMethod interface. It is placed on the methods in the SEI. The
@WebMethod annotation provides the information that is normally represented in the
wsdl:operation element describing the operation to which the method is associated.
Table 1.3 describes the properties of the
@WebMethod annotation.
Table 1.3. @WebMethod Properties
The @RequestWrapper annotation is defined by the
javax.xml.ws.RequestWrapper interface. It is placed on the methods in the SEI. The
@RequestWrapper annotation specifies the Java class implementing the wrapper bean for the method
parameters of the request message starting a message exchange. It also specifies the element names, and namespaces, used by the runtime
when marshalling and unmarshalling the request messages.
Table 1.4 describes the properties of the
@RequestWrapper annotation.
Table 1.4. @RequestWrapper Properties
| Property | Description |
|---|---|
| localName | Specifies the local name of the wrapper element in the XML representation of the request message. The default value is either the
name of the method, or the value of the
@WebMethod
annotation's operationName property. |
| targetNamespace | Specifies the namespace under which the XML wrapper element is defined. The default value is the target namespace of the SEI. |
| className | Specifies the full name of the Java class that implements the wrapper element. |
![]() | Tip |
|---|---|
Only the className property is required. |
![]() | Important |
|---|---|
If the method is also annotated with the |
The @ResponseWrapper annotation is defined by the
javax.xml.ws.ResponseWrapper interface. It is placed on the methods in the SEI. The
@ResponseWrapper specifies the Java class implementing the wrapper bean for the method parameters in the
response message in the message exchange. It also specifies the element names, and namespaces, used by the runtime when marshaling and
unmarshalling the response messages.
Table 1.5 describes the properties of the
@ResponseWrapper annotation.
Table 1.5. @ResponseWrapper Properties
| Property | Description |
|---|---|
| localName | Specifies the local name of the wrapper element in the XML representation of the response message. The default value is either the
name of the method with Response appended, or the value of the
@WebMethod
annotation's operationName property with Response appended. |
| targetNamespace | Specifies the namespace where the XML wrapper element is defined. The default value is the target namespace of the SEI. |
| className | Specifies the full name of the Java class that implements the wrapper element. |
![]() | Tip |
|---|---|
Only the className property is required. |
![]() | Important |
|---|---|
If the method is also annotated with the |
The @WebFault annotation is defined by the javax.xml.ws.WebFault
interface. It is placed on exceptions that are thrown by your SEI. The @WebFault annotation is used to map the
Java exception to a wsdl:fault element. This information is used to marshall the exceptions into a representation that
can be processed by both the service and its consumers.
Table 1.6 describes the properties of the @WebFault
annotation.
![]() | Important |
|---|---|
The name property is required. |
The @Oneway annotation is defined by the javax.jws.Oneway
interface. It is placed on the methods in the SEI that will not require a response from the service. The @Oneway
annotation tells the run time that it can optimize the execution of the method by not waiting for a response and by not reserving any resources to
process a response.
This annotation can only be used on methods that meet the following criteria:
They return void
They have no parameters that implement the Holder interface
They do not throw any exceptions that can be passed back to a consumer
Example 1.6 shows an SEI with its methods annotated.
Example 1.6. SEI with Annotated Methods
package com.fusesource.demo; import javax.jws.*; import javax.xml.ws.*; @WebService(name="quoteReporter") public interface quoteReporter { @WebMethod(operationName="getStockQuote") @RequestWrapper(targetNamespace="http://demo.fusesource.com/types", className="java.lang.String") @ResponseWrapper(targetNamespace="http://demo.fusesource.com/types", className="org.eric.demo.Quote") public Quote getQuote(String ticker); }
The method parameters in the SEI correspond to the wsdl:message elements and their
wsdl:part elements. JAX-WS provides annotations that allow you to describe the
wsdl:part elements that are generated for the method parameters.
The @WebParam annotation is defined by the javax.jws.WebParam interface. It is placed on
the parameters of the methods defined in the SEI. The @WebParam annotation allows you to specify the direction
of the parameter, if the parameter will be placed in the SOAP header, and other properties of the generated wsdl:part.
Table 1.7 describes the properties of the @WebParam annotation.
Table 1.7. @WebParam Properties
| Property | Values | Description |
|---|---|---|
| name | Specifies the name of the parameter as it appears in the generated WSDL document. For RPC bindings, this is the name of the
wsdl:part representing the parameter. For document bindings, this is the local name of the XML element representing the parameter.
Per the JAX-WS specification, the default is arg, where N is replaced
with the zero-based argument index (i.e., arg0, arg1, etc.). | |
| targetNamespace | Specifies the namespace for the parameter. It is only used with document bindings where the parameter maps to an XML element. The default is to use the service's namespace. | |
| mode |
| Specifies the direction of the parameter. |
| header |
| Specifies if the parameter is passed as part of the SOAP header. |
| partName | Specifies the value of the name attribute of the wsdl:part element for the parameter. This property
is used for document style SOAP bindings. | |
[a] Any parameter that implements the | ||
The @WebResult annotation is defined by the javax.jws.WebResult interface. It is placed
on the methods defined in the SEI. The @WebResult annotation allows you to specify the properties of the
wsdl:part that is generated for the method's return value.
Table 1.8 describes the properties of the @WebResult annotation.
Table 1.8. @WebResult Properties
Example 1.7 shows an SEI that is fully annotated.
Example 1.7. Fully Annotated SEI
package com.fusesource.demo; import javax.jws.*; import javax.xml.ws.*; import javax.jws.soap.*; import javax.jws.soap.SOAPBinding.*; import javax.jws.WebParam.*; @WebService(targetNamespace="http://demo.fusesource.com", name="quoteReporter") @SOAPBinding(style=Style.RPC, use=Use.LITERAL) public interface quoteReporter { @WebMethod(operationName="getStockQuote") @RequestWrapper(targetNamespace="http://demo.fusesource.com/types", className="java.lang.String") @ResponseWrapper(targetNamespace="http://demo.fusesource.com/types", className="org.eric.demo.Quote") @WebResult(targetNamespace="http://demo.fusesource.com/types", name="updatedQuote") public Quote getQuote( @WebParam(targetNamespace="http://demo.fusesource.com/types", name="stockTicker", mode=Mode.IN) String ticker ); }
The @WSDLDocumentation annotation is defined by the
org.apache.cxf.annotations.WSDLDocumentation interface.
It can be placed on the SEI or the SEI methods.
This annotation enables you to add documentation, which will then appear within
wsdl:documentation elements after the SEI is converted to
WSDL. By default, the documentation elements appear inside the port type, but you
can specify the placement property to make the documentation appear at other locations
in the WSDL file. Table 1.9 shows the
properties supported by the @WSDLDocumentation
annotation.
Table 1.9. @WSDLDocumentation properties
| Property | Description |
|---|---|
value | (Required) A string containing the documentation text. |
placement | (Optional) Specifies where in the WSDL file this documentation is to appear. For the list of possible placement values, see Placement in the WSDL contract. |
faultClass | (Optional) If the placement is set to be
FAULT_MESSAGE, PORT_TYPE_OPERATION_FAULT, or
BINDING_OPERATION_FAULT, you must also set this property to the Java
class that represents the fault. |
The @WSDLDocumentationCollection annotation is defined
by the
org.apache.cxf.annotations.WSDLDocumentationCollection
interface. It can be placed on the SEI or the SEI methods.
This annotation is used to insert multiple documentation elements at a single placement location or at various placement locations.
To specify where the documentation should appear in the WSDL contract, you can specify
the placement property, which is of type
WSDLDocumentation.Placement. The placement can have one of the following
values:
WSDLDocumentation.Placement.BINDING
WSDLDocumentation.Placement.BINDING_OPERATION
WSDLDocumentation.Placement.BINDING_OPERATION_FAULT
WSDLDocumentation.Placement.BINDING_OPERATION_INPUT
WSDLDocumentation.Placement.BINDING_OPERATION_OUTPUT
WSDLDocumentation.Placement.DEFAULT
WSDLDocumentation.Placement.FAULT_MESSAGE
WSDLDocumentation.Placement.INPUT_MESSAGE
WSDLDocumentation.Placement.OUTPUT_MESSAGE
WSDLDocumentation.Placement.PORT_TYPE
WSDLDocumentation.Placement.PORT_TYPE_OPERATION
WSDLDocumentation.Placement.PORT_TYPE_OPERATION_FAULT
WSDLDocumentation.Placement.PORT_TYPE_OPERATION_INPUT
WSDLDocumentation.Placement.PORT_TYPE_OPERATION_OUTPUT
WSDLDocumentation.Placement.SERVICE
WSDLDocumentation.Placement.SERVICE_PORT
WSDLDocumentation.Placement.TOP
Example 1.8 shows how to add a
@WSDLDocumentation annotation to the SEI and to
one of its methods.
Example 1.8. Using @WSDLDocumentation
@WebService @WSDLDocumentation("A very simple example of an SEI") public interface HelloWorld { @WSDLDocumentation("A traditional form of greeting") String sayHi(@WebParam(name = "text") String text); }
When WSDL, shown in Example 1.9, is generated from the
SEI in Example 1.8, the default placements of the
documentation elements are, respectively,
PORT_TYPE and PORT_TYPE_OPERATION.
Example 1.9. WSDL generated with documentation
<wsdl:definitions ... > ... <wsdl:portType name="HelloWorld"> <wsdl:documentation>A very simple example of an SEI</wsdl:documentation> <wsdl:operation name="sayHi"> <wsdl:documentation>A traditional form of greeting</wsdl:documentation> <wsdl:input name="sayHi" message="tns:sayHi"> </wsdl:input> <wsdl:output name="sayHiResponse" message="tns:sayHiResponse"> </wsdl:output> </wsdl:operation> </wsdl:portType> ... </wsdl:definitions>
Example 1.10 shows how to add a
@WSDLDocumentationCollection annotation to an SEI.
Example 1.10. Using @WSDLDocumentationCollection
@WebService @WSDLDocumentationCollection( { @WSDLDocumentation("A very simple example of an SEI"), @WSDLDocumentation(value = "My top level documentation", placement = WSDLDocumentation.Placement.TOP), @WSDLDocumentation(value = "Binding documentation", placement = WSDLDocumentation.Placement.BINDING) } ) public interface HelloWorld { @WSDLDocumentation("A traditional form of Geeky greeting") String sayHi(@WebParam(name = "text") String text); }
The @SchemaValidation annotation is defined by the
org.apache.cxf.annotations.SchemaValidation interface. It is placed on the
SEI.
This annotation turns on schema validation of the XML messages sent to this endpoint. This can be useful for testing purposes, when you suspect there is a problem with the format of incoming XML messages. By default, validation is disabled, because it has a significant impact on performance.
Example 1.11 shows how to enable schema
validation of messages for endpoints based on the
HelloWorld SEI.
Example 1.11. Activating schema validation
@WebService @SchemaValidation public interface HelloWorld { String sayHi(@WebParam(name = "text") String text); }
The @DataBinding annotation is defined by the
org.apache.cxf.annotations.DataBinding interface. It is
placed on the SEI.
This annotation is used to associate a data binding with the SEI, replacing the
default JAXB data binding. The value of the @DataBinding
annotation must be the class that provides the data binding,
.ClassName.class
The following data bindings are currently supported by Fuse Services Framework:
org.apache.cxf.jaxb.JAXBDataBinding
(Default) The standard JAXB data binding.
org.apache.cxf.sdo.SDODataBinding
The Service Data Objects (SDO) data binding is based on the Apache Tuscany SDO
implementation. If you want to use this data binding in the context of a Maven build,
you need to add a dependency on the cxf-rt-databinding-sdo
artifact.
org.apache.cxf.aegis.databinding.AegisDatabinding
If you want to use this data binding in the context of a Maven build, you need to
add a dependency on the cxf-rt-databinding-aegis artifact.
org.apache.cxf.xmlbeans.XmlBeansDataBinding
If you want to use this data binding in the context of a Maven build, you need to
add a dependency on the cxf-rt-databinding-xmlbeans artifact.
org.apache.cxf.databinding.source.SourceDataBinding
This data binding belongs to the Apache CXF core.
org.apache.cxf.databinding.stax.StaxDataBinding
This data binding belongs to the Apache CXF core.
Example 1.12 shows how to associate the SDO binding
with the HelloWorld SEI
Example 1.12. Setting the data binding
@WebService @DataBinding(org.apache.cxf.sdo.SDODataBinding.class) public interface HelloWorld { String sayHi(@WebParam(name = "text") String text); }
The @GZIP annotation is defined by the
org.apache.cxf.annotations.GZIP interface. It is placed
on the SEI.
Enables GZIP compression of messages. GZIP is a negotiated enhancement. That is, an
initial request from a client will not be gzipped, but an Accept header will be
added and, if the server supports GZIP compression, the response will be gzipped and any
subsequent requests will be also.
Table 1.10 shows the optional properties
supported by the @GZIP annotation.
Table 1.10. @GZIP Properties
| Property | Description |
|---|---|
threshold | Messages smaller than the size specified by this property are not gzipped. Default is -1 (no limit). |
The @FastInfoset annotation is defined by the
org.apache.cxf.annotations.FastInfoset interface. It is
placed on the SEI.
Enables the use of FastInfoset format for messages. FastInfoset is a binary encoding format for XML, which aims to optimize both the message size and the processing performance of XML messages. For more details, see the following Sun article on Fast Infoset.
FastInfoset is a negotiated enhancement. That is, an initial request from a client will
not be in FastInfoset format, but an Accept header will be added and, if the
server supports FastInfoset, the response will be in FastInfoset and any subsequent requests
will be also.
Table 1.11 shows the optional properties
supported by the @FastInfoset annotation.
Table 1.11. @FastInfoset Properties
| Property | Description |
|---|---|
force | A boolean property that forces the use of FastInfoset format, instead of
negotiating. When true, force the use of FastInfoset format; otherwise,
negotiate. Default is false. |
Example 1.13 shows how to enable GZIP
compression for the HelloWorld SEI.
Example 1.13. Enabling GZIP
@WebService @GZIP public interface HelloWorld { String sayHi(@WebParam(name = "text") String text); }
Example 1.14 shows how to enable the
FastInfoset format for the HelloWorld SEI.
Example 1.14. Enabling FastInfoset
@WebService @FastInfoset public interface HelloWorld { String sayHi(@WebParam(name = "text") String text); }
The @Logging annotation is defined by the
org.apache.cxf.annotations.Logging interface. It is placed on the SEI.
This annotation enables logging for all endpoints associated with the SEI. Table 1.12 shows the optional properties you can set in this annotation.
Table 1.12. @Logging Properties
| Property | Description |
|---|---|
limit | Specifies the size limit, beyond which the message is truncated in the logs. Default is 64K. |
inLocation | Specifies the location to log incoming messages. Can be either
<stderr>, <stdout>, <logger>, or a
filename. Default is <logger>. |
outLocation | Specifies the location to log outgoing messages. Can be either
<stderr>, <stdout>, <logger>, or a
filename. Default is <logger>. |
Example 1.15 shows how to enable logging for the
HelloWorld SEI, where incoming messages are sent to
<stdout> and outgoing messages are sent to <logger>.
Example 1.15. Logging configuration using annotations
@WebService @Logging(limit=16000, inLocation="<stdout>") public interface HelloWorld { String sayHi(@WebParam(name = "text") String text); }
Both properties and policies can be used to associate configuration data with an
endpoint. The essential difference between them is that properties are
a Fuse Services Framework specific configuration mechanism whereas policies are a
standard WSDL configuration mechanism. Policies typically originate from WS specifications
and standards and they are normally set by defining wsdl:policy
elements that appear in the WSDL contract. By contrast, properties are Apache CXF-specific and they are
normally set by defining jaxws:properties elements in
the Fuse Services Framework Spring configuration file.
It is also possible, however, to define property settings and WSDL policy settings in Java using annotations, as described here.
The @EndpointProperty annotation is defined by the
org.apache.cxf.annotations.EndpointProperty interface. It is placed on the
SEI.
This annotation adds Apache CXF-specific configuration settings to an endpoint. Endpoint
properties can also be specified in a Spring configuration file. For example, to configure
WS-Security on an endpoint, you could add endpoint properties using the
jaxws:properties element in a Spring configuration file as follows:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" ... > <jaxws:endpoint id="MyService" address="https://localhost:9001/MyService" serviceName="interop:MyService" endpointName="interop:MyServiceEndpoint" implementor="com.foo.MyService"> <jaxws:properties> <entry key="ws-security.callback-handler" value="interop.client.UTPasswordCallback"/> <entry key="ws-security.signature.properties" value="etc/keystore.properties"/> <entry key="ws-security.encryption.properties" value="etc/truststore.properties"/> <entry key="ws-security.encryption.username" value="useReqSigCert"/> </jaxws:properties> </jaxws:endpoint> </beans>
Alternatively, you could specify the preceding configuration settings in Java by adding
@EndpointProperty annotations to the SEI, as shown in Example 1.16.
Example 1.16. Configuring WS-Security Using @EndpointProperty Annotations
@WebService @EndpointProperty(name="ws-security.callback-handler" value="interop.client.UTPasswordCallback") @EndpointProperty(name="ws-security.signature.properties" value="etc/keystore.properties") @EndpointProperty(name="ws-security.encryption.properties" value="etc/truststore.properties") @EndpointProperty(name="ws-security.encryption.username" value="useReqSigCert") public interface HelloWorld { String sayHi(@WebParam(name = "text") String text); }
The @EndpointProperties annotation is defined by the
org.apache.cxf.annotations.EndpointProperties interface. It is placed on the
SEI.
This annotation provides a way of grouping multiple @EndpointProperty
annotations into a list. Using @EndpointProperties, it is possible to re-write
Example 1.16 as shown in Example 1.17.
Example 1.17. Configuring WS-Security Using an @EndpointProperties Annotation
@WebService @EndpointProperties( { @EndpointProperty(name="ws-security.callback-handler" value="interop.client.UTPasswordCallback"), @EndpointProperty(name="ws-security.signature.properties" value="etc/keystore.properties"), @EndpointProperty(name="ws-security.encryption.properties" value="etc/truststore.properties"), @EndpointProperty(name="ws-security.encryption.username" value="useReqSigCert") }) public interface HelloWorld { String sayHi(@WebParam(name = "text") String text); }
The @Policy annotation is defined by the
org.apache.cxf.annotations.Policy interface. It can be placed on the SEI or
the SEI methods.
This annotation is used to associate a WSDL policy with an SEI or an SEI method. The
policy is specified by providing a URI that references an XML file containing a standard
wsdl:policy element. If a WSDL contract is to be generated from the SEI (for
example, using the java2ws command-line tool), you can specify whether or not
you want to include this policy in the WSDL.
Table 1.13 shows the properties
supported by the @Policy annotation.
Table 1.13. @Policy Properties
| Property | Description |
|---|---|
uri | (Required) The location of the file containing the policy definition. |
includeInWSDL | (Optional) Whether to include the policy in the generated
contract, when generating WSDL. Default is true. |
placement | (Optional) Specifies where in the WSDL file this documentation is to appear. For the list of possible placement values, see Placement in the WSDL contract. |
faultClass | (Optional) If the placement is set to be
BINDING_OPERATION_FAULT or PORT_TYPE_OPERATION_FAULT,
you must also set this property to specify which fault this policy applies to. The
value is the Java class that represents the fault. |
The @Policies annotation is defined by the
org.apache.cxf.annotations.Policies interface. It can be placed on the SEI or
thse SEI methods.
This annotation provides a way of grouping multiple @Policy annotations
into a list.
To specify where the policy should appear in the WSDL contract, you can specify the
placement property, which is of type Policy.Placement. The
placement can have one of the following values:
Policy.Placement.BINDING Policy.Placement.BINDING_OPERATION Policy.Placement.BINDING_OPERATION_FAULT Policy.Placement.BINDING_OPERATION_INPUT Policy.Placement.BINDING_OPERATION_OUTPUT Policy.Placement.DEFAULT Policy.Placement.PORT_TYPE Policy.Placement.PORT_TYPE_OPERATION Policy.Placement.PORT_TYPE_OPERATION_FAULT Policy.Placement.PORT_TYPE_OPERATION_INPUT Policy.Placement.PORT_TYPE_OPERATION_OUTPUT Policy.Placement.SERVICE Policy.Placement.SERVICE_PORT
The following example shows how to associate WSDL policies with the
HelloWorld SEI and how to associate a policy with the sayHi
method. The policies themselves are stored in XML files in the file system, under the
annotationpolicies directory.
@WebService @Policy(uri = "annotationpolicies/TestImplPolicy.xml", placement = Policy.Placement.SERVICE_PORT), @Policy(uri = "annotationpolicies/TestPortTypePolicy.xml", placement = Policy.Placement.PORT_TYPE) public interface HelloWorld { @Policy(uri = "annotationpolicies/TestOperationPTPolicy.xml", placement = Policy.Placement.PORT_TYPE_OPERATION), String sayHi(@WebParam(name = "text") String text); }
You can use the @Policies annotation to group multiple @Policy
annotations into a list, as shown in the following example:
@WebService @Policies({ @Policy(uri = "annotationpolicies/TestImplPolicy.xml", placement = Policy.Placement.SERVICE_PORT), @Policy(uri = "annotationpolicies/TestPortTypePolicy.xml", placement = Policy.Placement.PORT_TYPE) }) public interface HelloWorld { @Policy(uri = "annotationpolicies/TestOperationPTPolicy.xml", placement = Policy.Placement.PORT_TYPE_OPERATION), String sayHi(@WebParam(name = "text") String text); }
Once your code is annotated, you can generate a WSDL contract for your service using the
java2ws Maven plug-in's -wsdl option. For a detailed listing
of options for the java2ws Maven plug-in see
java2ws.
Example 1.18 shows how to set up the
java2ws Maven plug-in to generate WSDL.
Example 1.18. Generating WSDL from Java
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-java2ws-plugin</artifactId>
<version>${cxf.version}</version>
<executions>
<execution>
<id>process-classes</id>
<phase>process-classes</phase>
<configuration>
<className>className</className>
<genWsdl>true</genWsdl>
</configuration>
<goals>
<goal>java2ws</goal>
</goals>
</execution>
</executions>
</plugin>Example 1.19 shows the WSDL contract that is generated for the SEI shown in Example 1.7.
Example 1.19. Generated WSDL from an SEI
<?xml version="1.0" encoding="UTF-8"?> <wsdl:definitions targetNamespace="http://demo.eric.org/" xmlns:tns="http://demo.eric.org/" xmlns:ns1="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns2="http://demo.eric.org/types" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"> <wsdl:types> <xsd:schema> <xs:complexType name="quote"> <xs:sequence> <xs:element name="ID" type="xs:string" minOccurs="0"/> <xs:element name="time" type="xs:string" minOccurs="0"/> <xs:element name="val" type="xs:float"/> </xs:sequence> </xs:complexType> </xsd:schema> </wsdl:types> <wsdl:message name="getStockQuote"> <wsdl:part name="stockTicker" type="xsd:string"> </wsdl:part> </wsdl:message> <wsdl:message name="getStockQuoteResponse"> <wsdl:part name="updatedQuote" type="tns:quote"> </wsdl:part> </wsdl:message> <wsdl:portType name="quoteReporter"> <wsdl:operation name="getStockQuote"> <wsdl:input name="getQuote" message="tns:getStockQuote"> </wsdl:input> <wsdl:output name="getQuoteResponse" message="tns:getStockQuoteResponse"> </wsdl:output> </wsdl:operation> </wsdl:portType> <wsdl:binding name="quoteReporterBinding" type="tns:quoteReporter"> <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" /> <wsdl:operation name="getStockQuote"> <soap:operation style="rpc" /> <wsdl:input name="getQuote"> <soap:body use="literal" /> </wsdl:input> <wsdl:output name="getQuoteResponse"> <soap:body use="literal"/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="quoteReporterService"> <wsdl:port name="quoteReporterPort" binding="tns:quoteReporterBinding"> <soap:address location="http://localhost:9000/quoteReporterService" /> </wsdl:port> </wsdl:service> </wsdl:definitions>
You do not need a WSDL contract to develop a service consumer. You can create a service consumer from an annotated SEI. Along with the SEI you need to know the address at which the endpoint exposing the service is published, the QName of the service element that defines the endpoint exposing the service, and the QName of the port element defining the endpoint on which your consumer makes requests. This information can be specified in the SEI's annotations or provided separately.
To create a consumer without a WSDL contract you must do the following:
Create a Service object for the service on which
the consumer will invoke operations.
Add a port to the Service object.
Get a proxy for the service using the Service
object's getPort() method.
The javax.xml.ws.Service class represents the wsdl:service element which contains
the definition of all of the endpoints that expose a service. As such, it provides methods that allow you to get endpoints, defined by
wsdl:port elements, that are proxies for making remote invocations on a service.
![]() | Note |
|---|---|
The |
The Service class has two static create() methods that can be used to create a new
Service object. As shown in Example 2.1, both of the
create() methods take the QName of the wsdl:service element the
Service object will represent, and one takes a URI specifying the location of the WSDL contract.
![]() | Tip |
|---|---|
All services publish their WSDL contracts. For SOAP/HTTP services the URI is usually the URI for the service appended with
|
Example 2.1. Service create() Methods
public static Service create(URL wsdlLocation,
QName serviceName)
throws WebServiceException;public static Service create(QName serviceName)
throws WebServiceException;The value of the serviceName parameter is a QName. The value of its namespace part is the target namespace
of the service. The service's target namespace is specified in the targetNamespace property of the
@WebService annotation. The value of the QName's local part is the value of
wsdl:service element's name attribute. You can determine this value in one of
the following ways:
It is specified in the serviceName property of the @WebService
annotation.
You append Service to the value of the name property of the
@WebService annotation.
You append Service to the name of the SEI.
Example 2.2 shows code for creating a Service object
for the SEI shown in Example 1.7.
The code in Example 2.2 does the following:
Builds the QName for the service using the targetNamespace property and the name
property of the | ||||
Calls the single parameter
|
The endpoint information for a service is defined in a wsdl:port element, and the
Service object creates a proxy instance for each of the endpoints defined in a WSDL contract, if one is
specified. If you do not specify a WSDL contract when you create your Service object, the
Service object has no information about the endpoints that implement your service, and therefore
cannot create any proxy instances. In this case, you must provide the Service object with the information
needed to represent a wsdl:port element using the addPort()
method.
The Service class defines an addPort() method, shown in
Example 2.3, that is used in cases where there is no WSDL contract available to the
consumer implementation. The addPort() method allows you to give a Service object the
information, which is typically stored in a wsdl:port element, necessary to create a proxy for a service
implementation.
Example 2.3. The addPort() Method
void addPort(QName portName,
String bindingId,
String endpointAddress)
throws WebServiceException;The value of the portName is a QName. The value of its namespace part is the target namespace of the service.
The service's target namespace is specified in the targetNamespace property of the
@WebService annotation. The value of the QName's local part is the value of
wsdl:port element's name attribute. You can determine this value in one of the
following ways:
Specify it in the portName property of the @WebService annotation.
Append Port to the value of the name property of the
@WebService annotation.
Append Port to the name of the SEI.
The value of the bindingId parameter is a string that uniquely identifies the type of binding used by the
endpoint. For a SOAP binding you use the standard SOAP namespace: http://schemas.xmlsoap.org/soap/.
If the endpoint is not using a SOAP binding, the value of the bindingId parameter is determined by the binding
developer.
The value of the endpointAddress parameter is the address where the endpoint is published. For a SOAP/HTTP
endpoint, the address is an HTTP address. Transports other than HTTP use different address schemes.
Example 2.4 shows code for adding a port to the Service
object created in Example 2.2.
Example 2.4. Adding a Port to a Service Object
package com.fusesource.demo;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
public class Client
{
public static void main(String args[])
{
...
QName portName = new QName("http://demo.fusesource.com", "stockQuoteReporterPort");
s.addPort(portName,
"http://schemas.xmlsoap.org/soap/",
"http://localhost:9000/StockQuote");
...
}
}The code in Example 2.4 does the following:
A service proxy is an object that provides all of the methods exposed by a remote service and handles all of the details required
to make the remote invocations. The Service object provides service proxies for all of the endpoints it is aware
of through the getPort() method. Once you have a service proxy, you can invoke its methods. The proxy forwards
the invocation to the remote service endpoint using the connection details specified in the service's contract.
The getPort() method, shown in Example 2.5, returns a
service proxy for the specified endpoint. The returned proxy is of the same class as the SEI.
Example 2.5. The getPort() Method
public <T> T getPort(QName portName,
Class<T> serviceEndpointInterface)
throws WebServiceException;The value of the portName parameter is a QName that identifies the wsdl:port
element that defines the endpoint for which the proxy is created. The value of the serviceEndpointInterface
parameter is the fully qualified name of the SEI.
![]() | Tip |
|---|---|
When you are working without a WSDL contract the value of the |
Example 2.6 shows code for getting a service proxy for the endpoint added in Example 2.4.
Example 2.6. Getting a Service Proxy
package com.fusesource.demo;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
public class Client
{
public static void main(String args[])
{
...
quoteReporter proxy = s.getPort(portName, quoteReporter.class);
...
}
}Once you instantiate a service proxy for a remote endpoint, you can invoke its methods as if it were a local object. The calls block until the remote method completes.
![]() | Note |
|---|---|
If a method is annotated with the |
Example 2.7 shows a consumer for the service defined in Example 1.7.
Example 2.7. Consumer Implemented without a WSDL Contract
package com.fusesource.demo;
import java.io.File;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
public class Client
{
public static void main(String args[])
{
QName serviceName = new QName("http://demo.eric.org", "stockQuoteReporter");
Service s = Service.create(serviceName);
QName portName = new QName("http://demo.eric.org", "stockQuoteReporterPort");
s.addPort(portName, "http://schemas.xmlsoap.org/soap/", "http://localhost:9000/EricStockQuote");
quoteReporter proxy = s.getPort(portName, quoteReporter.class);
Quote quote = proxy.getQuote("ALPHA");
System.out.println("Stock "+quote.getID()+" is worth "+quote.getVal()+" as of "+quote.getTime());
}
}The code in Example 2.7 does the following:
Another way to develop services is to start with a WSDL contract. The WSDL contract provides an implementation neutral way of defining the operations a service exposes and the data that is exchanged with the service. Fuse Services Framework provides tools to generate JAX-WS annotated starting point code from a WSDL contract. The code generators create all of the classes necessary to implement any abstract data types defined in the contract.
Table of Contents
Example 3.1 shows the HelloWorld WSDL contract. This contract
defines a single interface, Greeter, in the wsdl:portType element. The contract
also defines the endpoint which will implement the service in the wsdl:port element.
Example 3.1. HelloWorld WSDL Contract
<?xml version="1.0" encoding=";UTF-8"?> <wsdl:definitions name="HelloWorld" targetNamespace="http://apache.org/hello_world_soap_http" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://apache.org/hello_world_soap_http" xmlns:x1="http://apache.org/hello_world_soap_http/types" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <wsdl:types> <schema targetNamespace="http://apache.org/hello_world_soap_http/types" xmlns="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"><element name="sayHi"> <element name="sayHi"> <complexType> <sequence> <element name="requestType" type="string"/> </sequence> </complexType> </element> <element name="sayHiResponse"> <complexType> <sequence> <element name="responseType" type="string"/> </sequence> </complexType> </element> <element name="greetMe"> <complexType> <sequence> <element name="requestType" type="string"/> </sequence> </complexType> </element> <element name="greetMeResponse"> <complexType> <sequence> <element name="responseType" type="string"/> </sequence> </complexType> </element> <element name="greetMeOneWay"> <complexType> <sequence> <element name="requestType" type="string"/> </sequence> </complexType> </element> <element name="pingMe"> <complexType/> </element> <element name="pingMeResponse"> <complexType/> </element> <element name="faultDetail"> <complexType> <sequence> <element name="minor" type="short"/> <element name="major" type="short"/> </sequence> </complexType> </element> </schema> </wsdl:types> <wsdl:message name="sayHiRequest"> <wsdl:part element="x1:sayHi" name="in"/> </wsdl:message> <wsdl:message name="sayHiResponse"> <wsdl:part element="x1:sayHiResponse" name="out"/> </wsdl:message> <wsdl:message name="greetMeRequest"> <wsdl:part element="x1:greetMe" name="in"/> </wsdl:message> <wsdl:message name="greetMeResponse"> <wsdl:part element="x1:greetMeResponse" name="out"/> </wsdl:message> <wsdl:message name="greetMeOneWayRequest"> <wsdl:part element="x1:greetMeOneWay" name="in"/> </wsdl:message> <wsdl:message name="pingMeRequest"> <wsdl:part name="in" element="x1:pingMe"/> </wsdl:message> <wsdl:message name="pingMeResponse"> <wsdl:part name="out" element="x1:pingMeResponse"/> </wsdl:message> <wsdl:message name="pingMeFault"> <wsdl:part name="faultDetail" element="x1:faultDetail"/> </wsdl:message> <wsdl:portType name="Greeter"><wsdl:operation name="sayHi"> <wsdl:input message="tns:sayHiRequest" name="sayHiRequest"/> <wsdl:output message="tns:sayHiResponse" name="sayHiResponse"/> </wsdl:operation>
<wsdl:operation name="greetMe"> <wsdl:input message="tns:greetMeRequest" name="greetMeRequest"/> <wsdl:output message="tns:greetMeResponse" name="greetMeResponse"/> </wsdl:operation>
<wsdl:operation name="greetMeOneWay"> <wsdl:input message="tns:greetMeOneWayRequest" name="greetMeOneWayRequest"/> </wsdl:operation>
<wsdl:operation name="pingMe"> <wsdl:input name="pingMeRequest" message="tns:pingMeRequest"/> <wsdl:output name="pingMeResponse" message="tns:pingMeResponse"/> <wsdl:fault name="pingMeFault" message="tns:pingMeFault"/> </wsdl:operation> </wsdl:portType> <wsdl:binding name="Greeter_SOAPBinding" type="tns:Greeter"> ... </wsdl:binding> <wsdl:service name="SOAPService"> <wsdl:port binding="tns:Greeter_SOAPBinding" name="SoapPort"> <soap:address location="http://localhost:9000/SoapContext/SoapPort"/> </wsdl:port> </wsdl:service> </wsdl:definitions>
The Greeter interface defined in
Example 3.1 defines the following operations:
sayHi — Has a single output parameter, of xsd:string. | |
greetMe — Has an input parameter, of xsd:string, and an output parameter, of xsd:string. | |
greetMeOneWay — Has a single input parameter, of xsd:string. Because this operation has no output parameters, it is optimized to be a oneway invocation (that is, the consumer does not wait for a response from the server). | |
pingMe — Has no input parameters and no output parameters, but it can raise a fault exception. |
In the top-down method of developing a service provider you start from a WSDL document that defines the operations and methods the service provider will implement. Using the WSDL document, you generate starting point code for the service provider. Adding the business logic to the generated code is done using normal Java programming APIs.
Once you have a WSDL document, the process for developing a JAX-WS service provider is as follows:
JAX-WS specifies a detailed mapping from a service defined in WSDL to the Java classes that will implement that service as a service
provider. The logical interface, defined by the wsdl:portType element, is mapped to a service endpoint interface
(SEI). Any complex types defined in the WSDL are mapped into Java classes following the mapping defined by the Java Architecture for XML
Binding (JAXB) specification. The endpoint defined by the wsdl:service element is also generated into a Java
class that is used by consumers to access service providers implementing the service.
The cxf-codegen-plugin Maven plug-in generates this code. It also provides
options for generating starting point code for your implementation. The code generator provides a number of
options for controlling the generated code.
Example 4.1 shows how to use the code generator to generate starting point code for a service.
Example 4.1. Service Code Generation
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>${cxf.version}</version>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<configuration>
<sourceRoot>outputDir</sourceRoot>
<wsdlOptions>
<wsdlOption>
<wsdl>wsdl</wsdl>
<extraargs>
<extraarg>-server</extraarg>
<extraarg>-impl</extraarg>
</extraargs>
</wsdlOption>
</wsdlOptions>
</configuration>
<goals>
<goal>wsdl2java</goal>
</goals>
</execution>
</executions>
</plugin>This does the following:
The -impl option generates a shell implementation class for each
wsdl:portType element in the WSDL contract.
The -server option generates a simple main() to run your service provider as
a stand alone application.
The sourceRoot specifies that the generated code
is written to a directory called outputDir.
wsdl element specifies the WSDL contract from which
code is generated.
For a complete list of the options for the code generator see cxf-codegen-plugin.
Table 4.1 describes the files generated for creating a service provider.
Table 4.1. Generated Classes for a Service Provider
| File | Description |
|---|---|
| The SEI. This file contains the interface your service provider implements. You should not edit this file. |
| The endpoint. This file contains the Java class consumers use to make requests on the service. |
| The skeleton implementation class. Modify this file to build your service provider. |
| A basic server mainline that allows you to deploy your service provider as a stand alone process. For more information see Publishing a Service. |
In addition, the code generator will generate Java classes for all of the types defined in the WSDL contract.
The generated code is placed into packages based on the namespaces used in the WSDL contract. The classes generated to support
the service (based on the wsdl:portType element, the wsdl:service element, and
the wsdl:port element) are placed in a package based on the target namespace of the WSDL contract. The
classes generated to implement the types defined in the types element of the contract are placed in a package
based on the targetNamespace attribute of the types element.
The mapping algorithm is as follows:
The leading http:// or urn:// are stripped off the namespace.
If the first string in the namespace is a valid Internet domain, for example it ends in .com or
.gov, then the leading www. is stripped off the string, and the two remaining components
are flipped.
If the final string in the namespace ends with a file extension of the pattern .xxx or .xx,
then the extension is stripped.
The remaining strings in the namespace are appended to the resulting string and separated by dots.
All letters are made lowercase.
You generate the implementation class used to build your service provider with the
code generator's -impl flag.
![]() | Tip |
|---|---|
If your service's contract includes any custom types defined in XML Schema, you must ensure that the classes for the types are generated and available. |
For more information on using the code generator see cxf-codegen-plugin.
The implementation code consists of two files:
— The service interface(SEI) for the service.portTypeName.java
— The class you will use to implement the
operations defined by the service.portTypeNameImpl.java
To provide the business logic for your service's operations complete the stub methods in
. You usually use standard Java to implement the business logic.
If your service uses custom XML Schema types, you must use the generated classes for each type to manipulate them. There are also some
Fuse Services Framework specific APIs that can be used to access some advanced features.portTypeNameImpl.java
For example, an implementation class for the service defined in Example 3.1 may look like Example 4.2. Only the code portions highlighted in bold must be inserted by the programmer.
Example 4.2. Implementation of the Greeter Service
package demo.hw.server; import org.apache.hello_world_soap_http.Greeter; @javax.jws.WebService(portName = "SoapPort", serviceName = "SOAPService", targetNamespace = "http://apache.org/hello_world_soap_http", endpointInterface = "org.apache.hello_world_soap_http.Greeter") public class GreeterImpl implements Greeter { public String greetMe(String me) { System.out.println("Executing operation greetMe"); System.out.println("Message received: " + me + "\n"); return "Hello " + me; } public void greetMeOneWay(String me) { System.out.println("Executing operation greetMeOneWay\n"); System.out.println("Hello there " + me); } public String sayHi() { System.out.println("Executing operation sayHi\n"); return "Bonjour"; } public void pingMe() throws PingMeFault { FaultDetail faultDetail = new FaultDetail(); faultDetail.setMajor((short)2); faultDetail.setMinor((short)1); System.out.println("Executing operation pingMe, throwing PingMeFault exception\n"); throw new PingMeFault("PingMeFault raised by server", faultDetail); } }
One way method of creating a consumer is to start from a WSDL contract. The contract defines the operations, messages, and transport details of the service on which a consumer makes requests. The starting point code for the consumer is generated from the WSDL contract. The functionality required by the consumer is added to the generated code.
The cxf-codegen-plugin Maven plug-in generates the stub code from the WSDL
contract. The stub code provides the supporting code that is required to invoke operations
on the remote service.
For consumers, the cxf-codegen-plugin Maven plug-in generates the following
types of code:
Stub code — Supporting files for implementing a consumer.
Starting point code — Sample code that connects to the remote service and invokes every operation on the remote service.
To generate consumer code use the cxf-codegen-plugin Maven plug-in.
Example 5.1 shows how to use the code generator
to generate consumer code.
Example 5.1. Consumer Code Generation
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>${cxf.version}</version>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<configuration>
<sourceRoot>outputDir</sourceRoot>
<wsdlOptions>
<wsdlOption>
<wsdl>wsdl</wsdl>
<extraargs>
<extraarg>-client</extraarg>
</extraargs>
</wsdlOption>
</wsdlOptions>
</configuration>
<goals>
<goal>wsdl2java</goal>
</goals>
</execution>
</executions>
</plugin>Where outputDir is the location of a directory where the
generated files are placed and wsdl specifies the WSDL
contract's location. The -client option generates starting point code for
the consumer's main() method.
For a complete list of the arguments available for the cxf-codegen-plugin
Maven plug-in see cxf-codegen-plugin.
The code generation plug-in generates the following Java packages for the contract shown in Example 3.1:
org.apache.hello_world_soap_http — This package is generated from the
http://apache.org/hello_world_soap_http target namespace. All of the WSDL entities defined in this
namespace (for example, the Greeter port type and the SOAPService service) map to Java classes this Java package.
org.apache.hello_world_soap_http.types — This package is generated from the
http://apache.org/hello_world_soap_http/types target namespace. All of the XML types defined in
this namespace (that is, everything defined in the wsdl:types element of the HelloWorld contract) map
to Java classes in this Java package.
The stub files generated by the cxf-codegen-plugin Maven plug-in fall
into the following categories:
Classes representing WSDL entities in the org.apache.hello_world_soap_http package. The following classes are generated to represent WSDL entities:
Greeter — A Java interface that represents the Greeter
wsdl:portType element. In JAX-WS terminology, this Java interface is the service endpoint interface
(SEI).
SOAPService — A Java service class (extending javax.xml.ws.Service) that
represents the SOAPService wsdl:service element.
PingMeFault — A Java exception class (extending
java.lang.Exception) that represents the pingMeFault wsdl:fault
element.
Classes representing XML types in the org.objectweb.hello_world_soap_http.types package. In the HelloWorld example, the only generated types are the various wrappers for the request and reply messages. Some of these data types are useful for the asynchronous invocation model.
To implement a consumer when starting from a WSDL contract, you must use the following stubs:
Service class
SEI
Using these stubs, the consumer code instantiates a service proxy to make requests on the remote service. It also implements the consumer's business logic.
Example 5.2 shows the typical outline of a generated service class,
[2], which extends the ServiceName_Servicejavax.xml.ws.Service base class.
Example 5.2. Outline of a Generated Service Class
@WebServiceClient(name="..." targetNamespace="..." wsdlLocation="...") public classServiceNameextends javax.xml.ws.Service { ... publicServiceName(URL wsdlLocation, QName serviceName) { } publicServiceName() { } @WebEndpoint(name="...") publicSEIgetPortName() { } . . . }
The class in Example 5.2 defines
the following methods:ServiceName
— Constructs a
service object based on the data in the ServiceName(URL wsdlLocation, QName serviceName)wsdl:service element with the QName
ServiceName service in the WSDL contract that is obtainable from
wsdlLocation.
— The default constructor. It constructs a service object
based on the service name and the WSDL contract that were provided at the time the stub code was generated (for example, when
running the wsdl2java tool). Using this constructor presupposes that the WSDL contract remains available at a
specified location.ServiceName()
get — Returns a proxy for the endpoint defined by the
PortName()wsdl:port element with the name attribute equal to
PortName. A getter method is generated for every wsdl:port element defined
by the ServiceName service. A wsdl:service element that contains multiple
endpoint definitions results in a generated service class with multiple
get methods.PortName()
For every interface defined in the original WSDL contract, you can generate a corresponding SEI. A service endpoint interface is
the Java mapping of a wsdl:portType element. Each operation defined in the original
wsdl:portType element maps to a corresponding method in the SEI. The operation's parameters are mapped as
follows:
The input parameters are mapped to method arguments.
The first output parameter is mapped to a return value.
If there is more than one output parameter, the second and subsequent output parameters map to method arguments (moreover, the values of these arguments must be passed using Holder types).
For example, Example 5.3 shows the Greeter SEI, which is generated from the
wsdl:portType element defined in Example 3.1. For simplicity,
Example 5.3 omits the standard JAXB and JAX-WS annotations.
Example 5.3. The Greeter Service Endpoint Interface
package org.apache.hello_world_soap_http;
...
public interface Greeter
{
public String sayHi();
public String greetMe(String requestType);
public void greetMeOneWay(String requestType);
public void pingMe() throws PingMeFault;
}Example 5.4 shows the code that implements the HelloWorld consumer. The consumer connects to the SoapPort port on the SOAPService service and then proceeds to invoke each of the operations supported by the Greeter port type.
Example 5.4. Consumer Implementation Code
package demo.hw.client;
import java.io.File;
import java.net.URL;
import javax.xml.namespace.QName;
import org.apache.hello_world_soap_http.Greeter;
import org.apache.hello_world_soap_http.PingMeFault;
import org.apache.hello_world_soap_http.SOAPService;
public final class Client {
private static final QName SERVICE_NAME =
new QName("http://apache.org/hello_world_soap_http",
"SOAPService");
private Client()
{
}
public static void main(String args[]) throws Exception
{
if (args.length == 0)
{
System.out.println("please specify wsdl");
System.exit(1);
}
URL wsdlURL;
File wsdlFile = new File(args[0]);
if (wsdlFile.exists())
{
wsdlURL = wsdlFile.toURL();
}
else
{
wsdlURL = new URL(args[0]);
}
System.out.println(wsdlURL);
SOAPService ss = new SOAPService(wsdlURL,SERVICE_NAME);
Greeter port = ss.getSoapPort();
String resp;
System.out.println("Invoking sayHi...");
resp = port.sayHi();
System.out.println("Server responded with: " + resp);
System.out.println();
System.out.println("Invoking greetMe...");
resp = port.greetMe(System.getProperty("user.name"));
System.out.println("Server responded with: " + resp);
System.out.println();
System.out.println("Invoking greetMeOneWay...");
port.greetMeOneWay(System.getProperty("user.name"));
System.out.println("No response from server as method is OneWay");
System.out.println();
try {
System.out.println("Invoking pingMe, expecting exception...");
port.pingMe();
} catch (PingMeFault ex) {
System.out.println("Expected exception: PingMeFault has occurred.");
System.out.println(ex.toString());
}
System.exit(0);
}
}The Client.main() method from Example 5.4 proceeds as follows:
When developing consumers using the JAX-WS APIs you are must provide a hard coded path to the WSDL document that defines your service. While this is OK in a small environment, using hard coded paths does not translate to enterprise deployments.
To address this issue, Fuse Services Framework provides three mechanisms for removing the requirement of using hard coded paths:
![]() | Tip |
|---|---|
Injecting the proxy into your implementation code is generally the best option. |
Fuse Services Framework's use of the Spring Framework allows you to avoid the hassle of using the JAX-WS APIs to create service proxies. It allows you to define a client endpoint in a configuration file and then inject a proxy directly into the implementation code. When the runtime instantiates the implementation object, it will also instantiate a proxy for the external service based on the configuration. The implementation is handed a reference to the instantiated proxy.
Because the proxy is instantiated using information in the configuration file, the WSDL location does not need to be hard coded. It can be changed at deployment time. You can also specify that the runtime should search the application's classpath for the WSDL.
To inject a proxy for an external service into a service provider's implementation do the following:
Deploy the required WSDL documents in a well known location that all parts of the application can access.
![]() | Tip |
|---|---|
If you are deploying the application as a WAR file, it is recommended that you place all of the WSDL documents and XML Schema documents
in the |
![]() | Tip |
|---|---|
If you are deploying the application as a JAR file, it is recommended that you place all of the WSDL documents and XML Schema documents
in the |
Configure a JAX-WS client endpoint for the proxy that is being injected.
Inject the proxy into your service provide using the
@Resource annotation.
You configure a JAX-WS client endpoint using the jaxws:client element in you application's configuration file. This
tells the runtime to instantiate a org.apache.cxf.jaxws.JaxWsClientProxy object with the specified properties. This object is the
proxy that will be injected into the service provider.
At a minimum you need to provide values for the following attributes:
id—Specifies the ID used to identify the client to be injected.
serviceClass—Specifies the SEI of the service on which the proxy makes requests.
Example 6.1 shows the configuration for a JAX-WS client endpoint.
Example 6.1. Configuration for a Proxy to be Injected into a Service Implementation
<beans ... xmlns:jaxws="http://cxf.apache.org/jaxws" ... schemaLocation="... http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd ..."> <jaxws:client id="bookClient" serviceClass="org.apache.cxf.demo.BookService" wsdlLocation="classpath:books.wsdl"/> ... </beans>
![]() | Note |
|---|---|
In Example 6.1 the |
For more information on configuring a JAX-WS client see Configuring Consumer Endpoints in Configuring Web Service Endpoints.
You inject the configured proxy into a service implementation as a resource using the @Resource
as shown in Example 6.2.
Example 6.2. Injecting a Proxy into a Service Implementation
package demo.hw.server; import org.apache.hello_world_soap_http.Greeter; @javax.jws.WebService(portName = "SoapPort", serviceName = "SOAPService", targetNamespace = "http://apache.org/hello_world_soap_http", endpointInterface = "org.apache.hello_world_soap_http.Greeter") public class StoreImpl implements Store { @Resource(name="bookClient") private BookService proxy; }
The annotation's name property corresponds to the value of the JAX-WS client's
id attribute. The configured proxy is injected into the BookService object
declared immediately after the annotation. You can use this object to make invocations on the proxy's external service.
The JAX-WS specification mandates the all implementations support:
a standard catalog facility to be used when resolving any Web service document that is part of the description of a Web service, specifically WSDL and XML Schema documents.
This catalog facility uses the XML catalog facility specified by OASIS. All of the JAX-WS APIs and annotation that take a WSDL URI use the catalog to resolve the WSDL document's location.
This means that you can provide an XML catalog file that rewrites the locations of your WSDL documents to suite specific deployment environments.
JAX-WS catalogs are standard XML catalogs as defined by the OASIS XML Catalogs 1.1 specification. They allow you to specify mapping:
a document's public identifier and/or a system identifier to a URI.
the URI of a resource to another URI.
Table 6.1 lists some common elements used for WSDL location resolution.
Table 6.1. Common JAX-WS Catalog Elements
| Element | Description |
|---|---|
uri | Maps a URI to an alternate URI. |
rewriteURI | Rewrites the beginning of a URI. For example, this element allows you to map all URIs that start with http://cxf.apache.org to URIs that
start with classpath:. |
uriSuffix | Maps a URI to an alternate URI based on the suffix of the original URI. For example you could map all URIs that end in
foo.xsd to classpath:foo.xsd. |
The JAX-WS specification mandates that the catalog used to resolve WSDL and XML Schema documents is assembled using all available resources named
META-INF/jax-ws-catalog.xml. If your application is packaged into a single JAR, or WAR, you can place the catalog into a single file.
If your application is packaged as multiple JARs, you can split the catalog into a number of files. Each catalog file could be modularized to only deal with WSDLs accessed by the code in the specific JARs.
The most involved mechanism for resolving WSDL document locations at runtime is to implement your own custom contract resolver.
This requires that you provide an implementation of the Fuse Services Framework specific ServiceContractResolver
interface. You also need to register your custom resolver with the bus.
Once properly registered, the custom contract resolver will be used to resolve the location of any required WSDL and schema documents.
A contract resolver is an implementation of the org.apache.cxf.endpoint.ServiceContractResolver
interface. As shown in Example 6.3, this interface has a single method,
getContractLocation(), that needs to be implemented. getContractLocation()
takes the QName of a service and returns the URI for the service's WSDL contract.
Example 6.3. ServiceContractResolver Interface
public interface ServiceContractResolver
{
URI getContractLocation(QName qname);
}The logic used to resolve the WSDL contract's location is application specific. You can add logic that to resolve contract locations from a UDDI registry, a database, a custom location on a file system, or any other mechanism you choose.
Before the Fuse Services Framework runtime will use your contract resolver, you must register it with a contract resolver registry. Contract resolver registries implement the
org.apache.cxf.endpoint.ServiceContractResolverRegistry interface. However, you do not need to implement your own registry.
Fuse Services Framework provides a default implementation in the org.apache.cxf.endpoint.ServiceContractResolverRegistryImpl class.
To register a contract resolver with the default registry you do the following:
Get a reference to the default bus object.
Get the service contract registry from the bus using the bus' getExtension()
method.
Create an instance of your contract resolver.
Register your contract resolver with the registry using the registry's register() method.
Example 6.4 shows the code for registering a contract resolver with the default registry.
The code in Example 6.4 does the following:
You can also implement a contract resolver so that it can be added to a client through configuration. The contract resolver is implemented in such a way that when the runtime reads the configuration and instantiates the resolver, the resolver registers itself. Because the runtime handles the initialization, you can decide at runtime if a client needs to use the contract resolver.
To implement a contract resolver so that it can be added to a client through configuration do the following:
Add an init() method to your contract resolver implementation.
Add logic to your init() method that registers the contract resolver with the
contract resolver registry as shown in Example 6.4.
Decorate the init() method with the @PostConstruct
annotation.
Example 6.5 shows a contract resolver implementation that can be added to a client using configuration.
Example 6.5. Service Contract Resolver that can be Registered Using Configuration
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.xml.namespace.QName;
import org.apache.cxf.Bus;
import org.apache.cxf.BusFactory;
public class UddiResolver implements ServiceContractResolver
{
private Bus bus;
...
@PostConstruct
public void init()
{
BusFactory bf=BusFactory.newInstance();
Bus bus=bf.createBus();
if (null != bus)
{
ServiceContractResolverRegistry resolverRegistry = bus.getExtension(ServiceContractResolverRegistry.class);
if (resolverRegistry != null)
{
resolverRegistry.register(this);
}
}
}
public URI getContractLocation(QName serviceName)
{
...
}
}To register the contract resolver with a client you need to add a bean element to the client's
configuration. The bean element's class attribute is the name of the
class implementing the contract resolver.
Example 6.6 shows a bean for adding a configuration resolver implemented by the
org.apache.cxf.demos.myContractResolver class.
Example 6.6. Bean Configuring a Contract Resolver
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> ... <bean id="myResolver" class="org.apache.cxf.demos.myContractResolver" /> ... </beans>
When a new proxy is created, the runtime uses the contract registry resolver to locate the remote service's WSDL contract.
The contract resolver registry calls each contract resolver's getContractLocation() method in the
order in which the resolvers were registered. It returns the first URI returned from one of the registered contract resolvers.
If you registered a contract resolver that attempted to resolve the WSDL contract at a well known shared file system, it would be the only contract resolver used. However, if you subsequently registered a contract resolver that resolved WSDL locations using a UDDI registry, the registry could use both resolvers to locate a service's WSDL contract. The registry would first attempt to locate the contract using the shared file system contract resolver. If that contract resolver failed, the registry would then attempt to locate it using the UDDI contract resolver.
Table 7.1 lists some of the JAX-WS APIs that can throw the generic
WebServiceException exception.
Table 7.1. APIs that Throw WebServiceException
| API | Reason |
|---|---|
Binding.setHandlerChain() | There is an error in the handler chain configuration. |
BindingProvider.getEndpointReference() | The specified class is not assigned from a W3CEndpointReference. |
Dispatch.invoke() | There is an error in the Dispatch instance's configuration or an error occurred
while communicating with the service. |
Dispatch.invokeAsync() | There is an error in the Dispatch instance's configuration. |
Dispatch.invokeOneWay() | There is an error in the Dispatch instance's configuration or an error occurred
while communicating with the service. |
LogicalMessage.getPayload() | An error occurred when using a supplied JAXBContext to unmarshall the payload. The
cause field of the WebServiceException contains the original
JAXBException. |
LogicalMessage.setPayload() | An error occurred when setting the payload of the message. If the exception is thrown when using a
JAXBContext, the cause field of the
WebServiceException contains the original
JAXBException. |
WebServiceContext.getEndpointReference() | The specified class is not assigned from a W3CEndpointReference. |
Protocol exceptions are thrown when an error occurs during the processing of a request. All synchronous remote invocations can throw a protocol exception. The underlying cause occurs either in the consumer's message handling chain or in the service provider.
The JAX-WS specification defines a generic protocol exception. It also specifies a SOAP-specific protocol exception and an HTTP-specific protocol exception.
The JAX-WS specification defines three types of protocol exception. Which exception you catch depends on the transport and binding used by your application.
Table 7.2 describes the three types of protocol exception and when they are thrown.
Table 7.2. Types of Generic Protocol Exceptions
| Exception Class | When Thrown |
|---|---|
javax.xml.ws.ProtocolException | This exception is the generic protocol exception. It can be caught regardless of the protocol in use. It can be cast into a specific fault type if you are using the SOAP binding or the HTTP binding. When using the XML binding in combination with the HTTP or JMS transports, the generic protocol exception cannot be cast into a more specific fault type. |
javax.xml.ws.soap.SOAPFaultException | This exception is thrown by remote invocations when using the SOAP binding. For more information see Using the SOAP protocol exception. |
| javax.xml.ws.http.HTTPException | This exception is thrown when using the Fuse Services Framework HTTP binding to develop RESTful Web services. For more information see Developing RESTful Web Services. |
The SOAPFaultException exception wraps a SOAP fault. The underlying SOAP fault is stored
in the fault field as a javax.xml.soap.SOAPFault object.
If a service implementation needs to throw an exception that does not fit any of the custom exceptions created for the application,
it can wrap the fault in a SOAPFaultException using the exceptions creator and throw it back to the
consumer. Example 7.1 shows code for creating and throwing a
SOAPFaultException if the method is passed an invalid parameter.
Example 7.1. Throwing a SOAP Protocol Exception
public Quote getQuote(String ticker)
{
...
if(tickers.length()<3)
{
SOAPFault fault = SOAPFactory.newInstance().createFault();
fault.setFaultString("Ticker too short");
throw new SOAPFaultException(fault);
}
...
}When a consumer catches a SOAPFaultException exception they can retrieve the
underlying cause of the exception by examining the wrapped SOAPFault exception. As
shown in Example 7.2, the SOAPFault exception is retrieved
using the SOAPFaultException exception's getFault()
method.
Example 7.2. Getting the Fault from a SOAP Protocol Exception
...
try
{
proxy.getQuote(ticker);
}
catch (SOAPFaultException sfe)
{
SOAPFault fault = sfe.getFault();
...
}Fuse Services Framework provides a number of ways to publish a service as a service provider. How you publish a service depends on the deployment environment you are using. Many of the containers supported by Fuse Services Framework do not require writing logic for publishing endpoints. There are two exceptions:
deploying a server as a standalone Java application
deploying a server into an OSGi container without Spring-DM
For detailed information in deploying applications into the supported containers see Configuring Web Service Endpoints.
The javax.xml.ws.Enddpoint class does the work of publishing a JAX-WS service provider.
To publishing an endpoint do the following:
Create an Endpoint object for your service provider.
Publish the endpoint.
Stop the endpoint when application shuts down.
The Endpoint class provides methods for creating and publishing service providers. It also
provides a method that can create and publish a service provider in a single method call.
A service provider is instantiated using an Endpoint object. You instantiate an
Endpoint object for your service provider using one of the following methods:
static Endpoint create(Object implementor);This create() method returns an Endpoint for the specified
service implementation. The Endpoint object is created using the information provided by the
implementation class' javax.xml.ws.BindingType annotation, if it is present. If the annotation
is not present, the Endpoint uses a default SOAP 1.1/HTTP binding.
static Endpoint create(URI bindingID,
Object implementor);This create() method returns an Endpoint object for the
specified implementation object using the specified binding. This method overrides the binding information provided by the
javax.xml.ws.BindingType annotation, if it is present. If the
bindingID cannot be resolved, or it is null, the binding specified in the
javax.xml.ws.BindingType is used to create the Endpoint. If
neither the bindingID or the javax.xml.ws.BindingType can be
used, the Endpoint is created using a default SOAP 1.1/HTTP binding.
static Endpoint publish(String address,
Object implementor);The publish() method creates an Endpoint object for the
specified implementation, and publishes it. The binding used for the Endpoint object is determined
by the URL scheme of the provided address. The list of bindings available to the implementation are
scanned for a binding that supports the URL scheme. If one is found the Endpoint object is created
and published. If one is not found, the method fails.
![]() | Tip |
|---|---|
Using |
![]() | Important |
|---|---|
The implementation object passed to any of the |
You can publish a service provider using either of the following Endpoint methods:
void publish(String address);This publish() method publishes the service provider at the address specified.
![]() | Important |
|---|---|
The |
void publish(Object serverContext);This publish() method publishes the service provider based on the information provided
in the specified server context. The server context must define an address for the endpoint, and the context must also be
compatible with one of the service provider's available bindings.
When the service provider is no longer needed you should stop it using its stop() method. The stop()
method, shown in Example 8.1, shuts down the endpoint and cleans up any resources it is using.
![]() | Important |
|---|---|
Once the endpoint is stopped it cannot be republished. |
When you want to deploy your application as a plain java application you need to implement the logic for publishing your
endpoints in the application's main() method. Fuse Services Framework provides you two options for writing
your application's main() method.
use the main() method generated by the wsdl2java
tool
write a custom main() method that publishes the endpoints
The code generators -server flag makes the tool generate a simple server
mainline. The generated server mainline, as shown in Example 8.2, publishes one service
provider for each port element in the specified WSDL contract.
For more information see cxf-codegen-plugin.
Example 8.2 shows a generated server mainline.
Example 8.2. Generated Server Mainline
package org.apache.hello_world_soap_http;
import javax.xml.ws.Endpoint;
public class GreeterServer {
protected GreeterServer() throws Exception {
System.out.println("Starting Server");
Object implementor = new GreeterImpl();
String address = "http://localhost:9000/SoapContext/SoapPort";
Endpoint.publish(address, implementor);
}
public static void main(String args[]) throws Exception {
new GreeterServer();
System.out.println("Server ready...");
Thread.sleep(5 * 60 * 1000);
System.out.println("Server exiting");
System.exit(0);
}
}The code in Example 8.2 does the following:
If you used the Java first development model or you do not want to use the generated server mainline you can write your own. To write your server mainline you must do the following:
Instantiate an
javax.xml.ws.Endpoint object for the service provider.
Create an optional server context to use when publishing the service provider.
Publish the service provider
using one of the publish() methods.
Stop the service provider when the application is ready to exit.
Example 8.3 shows the code for publishing a service provider.
Example 8.3. Custom Server Mainline
package org.apache.hello_world_soap_http;
import javax.xml.ws.Endpoint;
public class GreeterServer
{
protected GreeterServer() throws Exception
{
}
public static void main(String args[]) throws Exception
{
GreeterImpl impl = new GreeterImpl();
Endpoint endpt.create(impl);
endpt.publish("http://localhost:9000/SoapContext/SoapPort");
boolean done = false;
while(!done)
{
...
}
endpt.stop();
System.exit(0);
}
}The code in Example 8.3 does the following:
When you develop an application that will be deployed into an OSGi container, you need to coordinate the publishing and stopping of your endpoints with the life-cycle of the bundle in which it is packaged. You want your endpoints published when the bundle is started and you want the endpoints stopped when the bundle is stopped.
You tie your endpoints life-cycle to the bundle's life-cycle by implementing an OSGi bundle activator. A bundle activator is used by the OSGi container to create the resource for a bundle when it is started. The container also uses the bundle activator to clean up the bundles resources when it is stopped.
You create a bundle activator for your application by implementing the
org.osgi.framework.BundleActivator interface. The BundleActivator
interface, shown in Example 8.4, it has two methods that need to be implemented.
Example 8.4. Bundle Activator Interface
interface BundleActivator
{
public void start(BundleContext context)
throws java.lang.Exception;
public void stop(BundleContext context)
throws java.lang.Exception;
}The start() method is called by the container when it starts the bundle. This is where you instantiate
and publish the endpoints.
The stop() method is called by the container when it stops the bundle. This is where you would stop
the endpoints.
The bundle activator's start method is where you publish your endpoints. To publish your endpoints the start method must do the following:
Instantiate an
javax.xml.ws.Endpoint object for the service provider.
Create an optional server context to use when publishing the service provider.
Publish the service provider
using one of the publish() methods.
Example 8.5 shows code for publishing a service provider.
Example 8.5. Bundle Activator Start Method for Publishing an Endpoint
package com.widgetvendor.osgi;
import javax.xml.ws.Endpoint;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
public class widgetActivator implements BundleActivator
{
private Endpoint endpt;
...
public void start(BundleContext context)
{
WidgetOrderImpl impl = new WidgetOrderImpl();
endpt = Endpoint.create(impl);
endpt.publish("http://localhost:9000/SoapContext/SoapPort");
}
...
}The code in Example 8.5 does the following:
The bundle activator's stop method is where you clean up the resources used by your application. Its implementation should include logic for stopping all of the endpoint's published by the application.
Example 8.6 shows a stop method for stopping a published endpoint.
Example 8.6. Bundle Activator Stop Method for Stopping an Endpoint
package com.widgetvendor.osgi;
import javax.xml.ws.Endpoint;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
public class widgetActivator implements BundleActivator
{
private Endpoint endpt;
...
public void stop(BundleContext context)
{
endpt.stop();
}
...
}You must add inform the container that the application's bundle includes a bundle activator. You do this by adding the Bundle-Activator property to the bundle's manifest. This property tells the container which class in the bundle to use when activating the bundle. Its value is the fully qualified name of the class implementing the bundle activator.
Example 8.7 shows a manifest entry for a bundle whose activator is implemented by
the class com.widgetvendor.osgi.widgetActivator.
Service-oriented design abstracts data into a common exchange format. Typically, this format is an XML grammar defined in XML Schema. To save the developer from working directly with XML documents, the JAX-WS specification calls for XML Schema types to be marshaled into Java objects. This marshaling is done in accordance with the Java Architecture for XML Binding (JAXB) specification. JAXB defines bindings for mapping between XML Schema constructs and Java objects and rules for how to marshal the data. It also defines an extensive customization framework for controlling how data is handled.
Table of Contents
JAXBContext ObjectFuse Services Framework supports the including and importing of schema definitions, using the
<include/> and <import/> schema tags. These tags enable you to
insert definitions from external files or resources into the scope of a schema element. The essential difference between including
and importing is:
Including brings in definitions that belong to the same target namespace as the enclosing schema element.
Importing brings in definitions that belong to a different target namespace from the enclosing schema element.
The include directive has the following syntax:
<include schemaLocation="anyURI" />The referenced schema, given by anyURI, must either belong to the same target namespace
as the enclosing schema, or not belong to any target namespace at all. If the referenced schema does not belong to any target
namespace, it is automatically adopted into the enclosing schema’s namespace when it is included.
Example 9.1 shows an example of an XML Schema document that includes another XML Schema document.
Example 9.1. Example of a Schema that Includes Another Schema
<definitions targetNamespace="http://schemas.fusesource.com/tests/schema_parser" xmlns:tns="http://schemas.fusesource.com/tests/schema_parser" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/"> <types> <schema targetNamespace="http://schemas.fusesource.com/tests/schema_parser" xmlns="http://www.w3.org/2001/XMLSchema"> <include schemaLocation="included.xsd"/> <complexType name="IncludingSequence"> <sequence> <element name="includedSeq" type="tns:IncludedSequence"/> </sequence> </complexType> </schema> </types> ... </definitions>
Example 9.2 shows the contents of the included schema file.
Example 9.2. Example of an Included Schema
<schema targetNamespace="http://schemas.fusesource.com/tests/schema_parser" xmlns="http://www.w3.org/2001/XMLSchema"> <!-- Included type definitions --> <complexType name="IncludedSequence"> <sequence> <element name="varInt" type="int"/> <element name="varString" type="string"/> </sequence> </complexType> </schema>
The import directive has the following syntax:
<import namespace="namespaceAnyURI" schemaLocation="schemaAnyURI" />
The imported definitions must belong to the namespaceAnyURI target namespace. If namespaceAnyURI is blank or remains unspecified, the imported schema definitions are unqualified.
Example 9.3 shows an example of an XML Schema that imports another XML Schema.
Example 9.3. Example of a Schema that Includes Another Schema
<definitions targetNamespace="http://schemas.fusesource.com/tests/schema_parser" xmlns:tns="http://schemas.fusesource.com/tests/schema_parser" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/"> <types> <schema targetNamespace="http://schemas.fusesource.com/tests/schema_parser" xmlns="http://www.w3.org/2001/XMLSchema"> <import namespace="http://schemas.fusesource.com/tests/imported_types" schemaLocation="included.xsd"/> <complexType name="IncludingSequence"> <sequence> <element name="includedSeq" type="tns:IncludedSequence"/> </sequence> </complexType> </schema> </types> ... </definitions>
Example 9.4 shows the contents of the imported schema file.
Example 9.4. Example of an Included Schema
<schema targetNamespace="http://schemas.fusesource.com/tests/imported_types" xmlns="http://www.w3.org/2001/XMLSchema"> <!-- Included type definitions --> <complexType name="IncludedSequence"> <sequence> <element name="varInt" type="int"/> <element name="varString" type="string"/> </sequence> </complexType> </schema>
Using types defined in a schema document that is not referenced in the service's WSDL document is a three step process:
Convert the schema document to a WSDL document using the xsd2wsdl tool.
Generate Java for the types using the wsdl2java tool on the generated WSDL document.
![]() | Important |
|---|---|
You will get a warning from the wsdl2java tool stating that the WSDL document does not define any services. You can ignore this warning. |
Add the generated classes to your classpath.
XML Schema type, group, and element definitions are scoped using namespaces. The namespaces prevent possible naming clashes between entities that use the same name. Java packages serve a similar purpose. Therefore, Fuse Services Framework maps the target namespace of a schema document into a package containing the classes necessary to implement the structures defined in the schema document.
The name of the generated package is derived from a schema's target namespace using the following algorithm:
The URI scheme, if present, is stripped.
![]() | Note |
|---|---|
Fuse Services Framework will only strip the |
For example, the namespace http:\\www.widgetvendor.com\types\widgetTypes.xsd
becomes \\widgetvendor.com\types\widgetTypes.xsd.
The trailing file type identifier, if present, is stripped.
For example, \\www.widgetvendor.com\types\widgetTypes.xsd becomes
\\widgetvendor.com\types\widgetTypes.
The resulting string is broken into a list of strings using / and : as
separators.
So, \\www.widgetvendor.com\types\widgetTypes becomes the list
{"www.widegetvendor.com", "types", "widgetTypes"}.
If the first string in the list is an internet domain name, it is decomposed as follows:
The leading www. is stripped.
The remaining string is split into its component parts using the . as the separator.
The order of the list is reversed.
So, {"www.widegetvendor.com", "types", "widgetTypes"} becomes
{"com", "widegetvendor", "types", "widgetTypes"}
![]() | Note |
|---|---|
Internet domain names end in one of the following: |
The strings are converted into all lower case.
So, {"com", "widegetvendor", "types", "widgetTypes"} becomes
{"com", "widegetvendor", "types", "widgettypes"}.
The strings are normalized into valid Java package name components as follows:
If the strings contain any special characters, the special characters are converted to an
underscore(_).
If any of the strings are a Java keyword, the keyword is prefixed with an underscore(_).
If any of the strings begin with a numeral, the string is prefixed with an underscore(_).
The strings are concatenated using . as a separator.
So, {"com", "widegetvendor", "types", "widgettypes"} becomes the package name
com.widgetvendor.types.widgettypes.
The XML Schema constructs defined in the namespace
http:\\www.widgetvendor.com\types\widgetTypes.xsd are mapped to the Java package
com.widgetvendor.types.widgettypes.
A JAXB generated package contains the following:
A class implementing each complex type defined in the schema
For more information on complex type mapping see Using Complex Types.
An enum type for any simple types defined using the enumeration facet
For more information on how enumerations are mapped see Enumerations.
A public ObjectFactory class that contains methods for instantiating objects from the
schema
For more information on the ObjectFactory class see
The Object Factory.
A package-info.java file that provides metadata about the classes in the package
JAXB uses an object factory to provide a mechanism for instantiating instances of JAXB generated constructs. The object factory contains methods for instantiating all of the XML schema defined constructs in the package's scope. The only exception is that enumerations do not get a creation method in the object factory.
For each Java class generated to implement an XML schema complex type, the object factory contains a method for creating an instance of the class. This method takes the form:
typeNamecreatetypeName();
For example, if your schema contained a complex type named widgetType, Fuse Services Framework generates a
class called WidgetType to implement it. Example 9.5 shows
the generated creation method in the object factory.
Example 9.5. Complex Type Object Factory Entry
public class ObjectFactory
{
...
WidgetType createWidgetType()
{
return new WidgetType();
}
...
}For elements that are declared in the schema's global scope, Fuse Services Framework inserts a factory method into the object factory.
As discussed in Using XML Elements, XML Schema elements are mapped to
JAXBElement<T> objects. The creation method takes the form:
public JAXBElement<elementType> createelementName(elementTypevalue);
For example if you have an element named comment of type xsd:string,
Fuse Services Framework generates the object factory method shown in Example 9.6
Example 9.6. Element Object Factory Entry
public class ObjectFactory
{
...
@XmlElementDecl(namespace = "...", name = "comment")
public JAXBElement<String> createComment(String value) {
return new JAXBElement<String>(_Comment_QNAME, String.class, null, value);
}
...
}When the Fuse Services Framework runtime reads and writes XML data it uses a map that associates the XML Schema types with their
representative Java types. By default, the map contains all of the types defined in the target namespace of the WSDL contract's
schema element. It also contains any types that are generated from the namespaces of any schemas
that are imported into the WSDL contract.
The addition of types from namespaces other than the schema namespace used by an application's
schema element is accomplished using the @XmlSeeAlso
annotation. If your application needs to work with types that are generated outside the scope of your application's WSDL document,
you can edit the @XmlSeeAlso annotation to add them to the JAXB map.
The @XmlSeeAlso annotation can be added to the SEI of your service. It contains a comma
separated list of classes to include in the JAXB context. Example 9.7 shows the
syntax for using the @XmlSeeAlso annotation.
Example 9.7. Syntax for Adding Classes to the JAXB Context
import javax.xml.bind.annotation.XmlSeeAlso; @WebService() @XmlSeeAlso({Class1.class,Class2.class, ...,ClassN.class}) public class GeneratedSEI { ... }
![]() | Tip |
|---|---|
In cases where you have access to the JAXB generated classes, it is more efficient to use the
|
Example 9.8 shows an SEI annotated with
@XmlSeeAlso.
Example 9.8. Adding Classes to the JAXB Context
... import javax.xml.bind.annotation.XmlSeeAlso; ... @WebService() @XmlSeeAlso({org.apache.schemas.types.test.ObjectFactory.class,org.apache.schemas.tests.group_test.ObjectFactory.class}) public interface Foo { ... }
XML Schema elements are used to define an instance of an element in an XML document. Elements are defined either in the global scope of an XML Schema document, or they are defined as a member of a complex type. When they are defined in the global scope, Fuse Services Framework maps them to a JAXB element class that makes manipulating them easier.
An element instance in an XML document is defined by an XML Schema element element in
the global scope of an XML Schema document To make it easier for Java developers to work with elements, Fuse Services Framework maps
globally scoped elements to either a special JAXB element class or to a Java class that is generated to match its content type.
How the element is mapped depends on if the element is defined using a named type referenced by the
type attribute or if the element is defined using an in-line type definition. Elements defined with
in-line type definitions are mapped to Java classes.
![]() | Tip |
|---|---|
It is recommended that elements are defined using a named type because in-line types are not reusable by other elements in the schema. |
In XML Schema elements are defined using element elements.
element elements has one required attribute. The name specifies
the name of the element as it appears in an XML document.
In addition to the name attribute element elements have the
optional attributes listed in Table 10.1.
Table 10.1. Attributes Used to Define an Element
| Attribute | Description |
|---|---|
type | Specifies the type of the element. The type can be any XML Schema primitive type or any named complex type defined in the contract. If this attribute is not specified, you will need to include an in-line type definition. |
nillable | Specifies if an element can be left out of a document entirely. If nillable is set to
true, the element can be omitted from any document generated using the schema. |
abstract | Specifies if an element can be used in an instance document. true indicates that the
element cannot appear in the instance document. Instead, another element whose
substitutionGroup attribute contains the QName of this element must appear in this
element's place. For information on how this attribute effects code generation see
Java mapping of abstract elements. |
substitutionGroup | Specifies the name of an element that can be substituted with this element. For more information on using type substitution see Element Substitution. |
default | Specifies a default value for an element. For information on how this attribute effects code generation see Java mapping of elements with a default value. |
fixed | Specifies a fixed value for the element. |
Example 10.1 shows a simple element definition.
An element can also define its own type using an in-line type definition. In-line types are specified using either a
complexType element or a simpleType element. Once you specify
whether the type of data is complex or simple, you can define any type of data needed using the tools available for each type of
data.
Example 10.2 shows an element definition with an in-line type definition.
Example 10.2. XML Schema Element Definition with an In-Line Type
<element name="skate"> <complexType> <sequence> <element name="numWheels" type="xsd:int" /> <element name="brand" type="xsd:string" /> </sequence> </complexType> </element>
By default, globally defined elements are mapped to JAXBElement<T> objects where the
template class is determined by the value of the element element's
type attribute. For primitive types, the template class is derived using the wrapper class mapping
described in Wrapper classes. For complex types, the Java class generated to support
the complex type is used as the template class.
To support the mapping and to relieve the developer of unnecessary worry about an element's QName, an object factory method is generated for each globally defined element, as shown in Example 10.3.
Example 10.3. Object Factory Method for a Globally Scoped Element
public class ObjectFactory {
private final static QName _name_QNAME = new QName("targetNamespace", "localName");
...
@XmlElementDecl(namespace = "targetNamespace", name = "localName")
public JAXBElement<type> createname(type value);
}For example, the element defined in Example 10.1 results in the object factory method shown in Example 10.4.
Example 10.4. Object Factory for a Simple Element
public class ObjectFactory {
private final static QName _JoeFred_QNAME = new QName("...", "joeFred");
...
@XmlElementDecl(namespace = "...", name = "joeFred")
public JAXBElement<String> createJoeFred(String value);
}Example 10.5 shows an example of using a globally scoped element in Java.
Example 10.5. Using a Globally Scoped Element
JAXBElement<String> element = createJoeFred("Green");
String color = element.getValue();If a globally scoped element is used to define a message part, the generated Java parameter is not an instance of
JAXBElement<T>. Instead it is mapped to a regular Java type or class.
Given the WSDL fragment shown in Example 10.6, the resulting method has a parameter of type String.
Example 10.6. WSDL Using an Element as a Message Part
<?xml version="1.0" encoding=";UTF-8"?> <wsdl:definitions name="HelloWorld" targetNamespace="http://apache.org/hello_world_soap_http" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://apache.org/hello_world_soap_http" xmlns:x1="http://apache.org/hello_world_soap_http/types" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <wsdl:types> <schema targetNamespace="http://apache.org/hello_world_soap_http/types" xmlns="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"><element name="sayHi"> <element name="sayHi" type="string"/> <element name="sayHiResponse" type="string"/> </schema> </wsdl:types> <wsdl:message name="sayHiRequest"> <wsdl:part element="x1:sayHi" name="in"/> </wsdl:message> <wsdl:message name="sayHiResponse"> <wsdl:part element="x1:sayHiResponse" name="out"/> </wsdl:message> <wsdl:portType name="Greeter"> <wsdl:operation name="sayHi"> <wsdl:input message="tns:sayHiRequest" name="sayHiRequest"/> <wsdl:output message="tns:sayHiResponse" name="sayHiResponse"/> </wsdl:operation> </wsdl:portType> ... </wsdl:definitions>
Example 10.7 shows the generated method signature for the
sayHi operation.
When an element is defined using an in-line type, it is mapped to Java following the same rules used for mapping other types to Java. The rules for simple types are described in Using Simple Types. The rules for complex types are described in Using Complex Types.
When a Java class is generated for an element with an in-line type definition, the generated class is decorated with the
@XmlRootElement annotation. The @XmlRootElement
annotation has two useful properties: name and namespace. These attributes
are described in Table 10.2.
Table 10.2. Properties for the @XmlRootElement Annotation
| Property | Description |
|---|---|
| name | Specifies the value of the XML Schema element element's
name attribute. |
| namespace | Specifies the namespace in which the element is defined. If this element is defined in the target namespace, the property is not specified. |
The @XmlRootElement annotation is not used if the element meets one or more of the
following conditions:
The element's nillable attribute is set to true
The element is the head element of a substitution group
For more information on substitution groups see Element Substitution.
When the element's abstract attribute is set to true the object
factory method for instantiating instances of the type is not generated. If the element is defined using an in-line type, the Java class
supporting the in-line type is generated.
When the element's default attribute is used the defaultValue
property is added to the generated @XmlElementDecl annotation. For example, the element
defined in Example 10.8 results in the object factory method shown in
Example 10.9.
Example 10.8. XML Schema Element with a Default Value
<element name="size" type="xsd:int" default="7"/>
Example 10.9. Object Factory Method for an Element with a Default Value
@XmlElementDecl(namespace = "...", name = "size", defaultValue = "7")
public JAXBElement<Integer> createUnionJoe(Integer value) {
return new JAXBElement<Integer>(_Size_QNAME, Integer.class, null, value);
}XML Schema simple types are either XML Schema primitive types like xsd:int, or are defined using the
simpleType element. They are used to specify elements that do not contain any children or attributes.
They are generally mapped to native Java constructs and do not require the generation of special classes to implement them.
Enumerated simple types do not result in generated code because they are mapped to Java enum types.
When a message part is defined using one of the XML Schema primitive types, the generated parameter's type is mapped to a corresponding Java native type. The same pattern is used when mapping elements that are defined within the scope of a complex type. The resulting field is of the corresponding Java native type.
Table 11.1 lists the mapping between XML Schema primitive types and Java native types.
Table 11.1. XML Schema Primitive Type to Java Native Type Mapping
| XML Schema Type | Java Type |
|---|---|
| xsd:string | String |
| xsd:integer | BigInteger |
| xsd:int | int |
| xsd:long | long |
| xsd:short | short |
| xsd:decimal | BigDecimal |
| xsd:float | float |
| xsd:double | double |
| xsd:boolean | boolean |
| xsd:byte | byte |
| xsd:QName | QName |
| xsd:dateTime | XMLGregorianCalendar |
| xsd:base64Binary | byte[] |
| xsd:hexBinary | byte[] |
| xsd:unsignedInt | long |
| xsd:unsignedShort | int |
| xsd:unsignedByte | short |
| xsd:time | XMLGregorianCalendar |
| xsd:date | XMLGregorianCalendar |
| xsd:g | XMLGregorianCalendar |
| xsd:anySimpleType [a] | Object |
| xsd:anySimpleType [b] | String |
| xsd:duration | Duration |
| xsd:NOTATION | QName |
[a] For elements of this type. [b] For attributes of this type. | |
Mapping XML Schema primitive types to Java primitive types does not work for all possible XML Schema constructs. Several cases require that an XML Schema primitive type is mapped to the Java primitive type's corresponding wrapper type. These cases include:
An element element with its nillable attribute set to
true as shown:
<element name="finned" type="xsd:boolean" nillable="true" />
An element element with its minOccurs attribute set to
0 and its maxOccurs attribute set to
1, or its maxOccurs attribute not specified, as shown :
<element name="plane" type="xsd:string" minOccurs="0" />
An attribute element with its use attribute set to
optional, or not specified, and having neither its default attribute
nor its fixed attribute specified, as shown:
<element name="date"> <complexType> <sequence/> <attribute name="calType" type="xsd:string" use="optional" /> </complexType> </element>
Table 11.2 shows how XML Schema primitive types are mapped into Java wrapper classes in these cases.
Table 11.2. Primitive Schema Type to Java Wrapper Class Mapping
| Schema Type | Java Type |
|---|---|
| xsd:int | java.lang.Integer |
| xsd:long | java.lang.Long |
| xsd:short | java.lang.Short |
| xsd:float | java.lang.Float |
| xsd:double | java.lang.Double |
| xsd:boolean | java.lang.Boolean |
| xsd:byte | java.lang.Byte |
| xsd:unsignedByte | java.lang.Short |
| xsd:unsignedShort | java.lang.Integer |
| xsd:unsignedInt | java.lang.Long |
| xsd:unsignedLong | java.math.BigInteger |
| xsd:duration | java.lang.String |
XML Schema allows you to create simple types by deriving a new type from another primitive type or simple type. Simple
types are described using a simpleType element.
The new types are described by restricting the base type with one or more facets. These facets limit the possible valid values that can be stored in the new type. For example, you could define a simple type, SSN, which is a string of exactly 9 characters.
Each of the primitive XML Schema types has their own set of optional facets.
To define your own simple type do the following:
Determine the base type for your new simple type.
Determine what restrictions define the new type based on the available facets for the chosen base type.
Using the syntax shown in this section, enter the appropriate simpleType element into the
types section of your contract.
Example 11.1 shows the syntax for describing a simple type.
Example 11.1. Simple type syntax
<simpleType name="typeName"> <restriction base="baseType"> <facetvalue="value" /> <facetvalue="value" /> ... </restriction> </simpleType>
The type description is enclosed in a simpleType element and
identified by the value of the name attribute. The base type
from which the new simple type is being defined is specified by the
base attribute of the
xsd:restriction element. Each facet element is specified within
the restriction element. The available facets and their valid
settings depend on the base type. For example, xsd:string has a number of
facets including:
length
minLength
maxLength
pattern
whitespace
Example 11.2 shows the definition for a simple type that represents the two-letter
postal code used for US states. It can only contain two, uppercase letters. TX is a valid value, but
tx or tX are not valid values.
Example 11.2. Postal Code Simple Type
<xsd:simpleType name="postalCode"> <xsd:restriction base="xsd:string"> <xsd:pattern value="[A-Z]{2}" /> </xsd:restriction> </xsd:simpleType>
Fuse Services Framework maps user-defined simple types to the Java type of the simple type’s base type. So, any message using the
simple type postalCode, shown in Example 11.2, is mapped to a
String because the base type of postalCode is xsd:string. For example,
the WSDL fragment shown in Example 11.3 results in a Java method,
state(), that takes a parameter, postalCode, of
String.
Example 11.3. Credit Request with Simple Types
<message name="stateRequest"> <part name="postalCode" type="postalCode" /> </message> ... <portType name="postalSupport"> <operation name="state"> <input message="tns:stateRequest" name="stateRec" /> <output message="tns:stateResponse" name="credResp" /> </operation> </portType>
By default, Fuse Services Framework does not enforce any of the facets that are used to restrict a simple type. However, you can configure Fuse Services Framework endpoints to enforce the facets by enabling schema validation.
To configure Fuse Services Framework endpoints to use schema validation set the schema-validation-enabled
property to true. Example 11.4 shows the configuration for a
service provider that uses schema validation
Example 11.4. Service Provider Configured to Use Schema Validation
<jaxws:endpoint name="{http://apache.org/hello_world_soap_http}SoapPort" wsdlLocation="wsdl/hello_world.wsdl" createdFromAPI="true"> <jaxws:properties> <entry key="schema-validation-enabled" value="true" /> </jaxws:properties> </jaxws:endpoint>
For more information on configuring Fuse Services Framework see Configuring Web Service Endpoints.
In XML Schema, enumerated types are simple types that are defined using the
xsd:enumeration facet. Unlike atomic simple types, they are mapped to Java
enums.
Enumerations are a simple type using the xsd:enumeration facet. Each
xsd:enumeration facet defines one possible value for the enumerated type.
Example 11.5 shows the definition for an enumerated type. It has the following possible values:
big
large
mungo
gargantuan
Example 11.5. XML Schema Defined Enumeration
<simpleType name="widgetSize"> <restriction base="xsd:string"> <enumeration value="big"/> <enumeration value="large"/> <enumeration value="mungo"/> <enumeration value="gargantuan"/> </restriction>
XML Schema enumerations where the base type is xsd:string are automatically mapped to Java enum type. You can instruct the code generator to map enumerations with other base types to Java enum types by using the customizations described in Customizing Enumeration Mapping.
The enum type is created as follows:
The name of the type is taken from the name attribute of the simple type definition and
converted to a Java identifier.
In general, this means converting the first character of the XML Schema's name to an uppercase letter. If the first
character of the XML Schema's name is an invalid character, an underscrore (_) is prepended to the
name.
For each enumeration facet, an enum constant is generated based on the value of the
value attribute.
The constant's name is derived by converting all of the lowercase letters in the value to their uppercase equivalent.
A constructor is generated that takes the Java type mapped from the enumeration's base type.
A public method called value() is generated to access the facet value that is represented
by an instance of the type.
The return type of the value() method is the base type of the XML Schema type.
A public method called fromValue() is generated to create an instance of the enum type
based on a facet value.
The parameter type of the value() method is the base type of the XML Schema
type.
The class is decorated with the @XmlEnum annotation.
The enumerated type defined in Example 11.5 is mapped to the enum type shown in Example 11.6.
Example 11.6. Generated Enumerated Type for a String Bases XML Schema Enumeration
@XmlType(name = "widgetSize") @XmlEnum public enum WidgetSize { @XmlEnumValue("big") BIG("big"), @XmlEnumValue("large") LARGE("large"), @XmlEnumValue("mungo") MUNGO("mungo"), @XmlEnumValue("gargantuan") GARGANTUAN("gargantuan"); private final String value; WidgetSize(String v) { value = v; } public String value() { return value; } public static WidgetSize fromValue(String v) { for (WidgetSize c: WidgetSize.values()) { if (c.value.equals(v)) { return c; } } throw new IllegalArgumentException(v); } }
XML Schema supports a mechanism for defining data types that are a list of space separated simple types. An example of
an element, primeList, using a list type is shown in
Example 11.7.
XML Schema list types are generally mapped to Java List<T> objects. The only variation to this pattern is when a message part is mapped directly to an instance of an XML Schema list type.
XML Schema list types are simple types and as such are defined using a simpleType element. The most common syntax used to define a list type is shown in Example 11.8.
Example 11.8. Syntax for XML Schema List Types
<simpleType name="listType"> <list itemType="atomicType"> <facet value="value" /> <facet value="value" /> ... </list> </simpleType>
The value given for atomicType defines the type of the elements in the list. It can only be one of the built in XML Schema atomic types, like xsd:int or xsd:string, or a user-defined simple type that is not a list.
In addition to defining the type of elements listed in the list type, you can also use facets to further constrain the properties of the list type. Table 11.3 shows the facets used by list types.
Table 11.3. List Type Facets
| Facet | Effect |
|---|---|
length | Defines the number of elements in an instance of the list type. |
minLength | Defines the minimum number of elements allowed in an instance of the list type. |
maxLength | Defines the maximum number of elements allowed in an instance of the list type. |
enumeration | Defines the allowable values for elements in an instance of the list type. |
pattern | Defines the lexical form of the elements in an instance of the list type. Patterns are defined using regular expressions. |
For example, the definition for the simpleList element shown in Example 11.7, is shown in Example 11.9.
Example 11.9. Definition of a List Type
<simpleType name="primeListType"> <list itemType="int"/> </simpleType> <element name="primeList" type="primeListType"/>
In addition to the syntax shown in Example 11.8 you can also define a list type using the less common syntax shown in Example 11.10.
Example 11.10. Alternate Syntax for List Types
<simpleType name="listType"> <list> <simpleType> <restriction base="atomicType"> <facet value="value"/> <facet value="value"/> ... </restriction> </simpleType> </list> </simpleType>
When an element is defined a list type, the list type is mapped to a collection property. A collection property is a Java
List<T> object. The template class used by the List<T> is the
wrapper class mapped from the list's base type. For example, the list type defined in
Example 11.9 is mapped to a List<Integer>.
For more information on wrapper type mapping see Wrapper classes.
When a message part is defined as a list type, or is mapped to an element of a list type, the resulting method parameter is
mapped to an array instead of a List<T> object. The base type of the array is the wrapper class
of the list type's base class.
For example, the WSDL fragment in Example 11.11 results in the method signature shown in Example 11.12.
Example 11.11. WSDL with a List Type Message Part
<definitions ...> ... <types ...> <schema ... > <simpleType name="primeListType"> <list itemType="int"/> </simpleType> <element name="primeList" type="primeListType"/> </schemas> </types> <message name="numRequest"> <part name="inputData" element="xsd1:primeList" /> </message> <message name="numResponse">; <part name="outputData" type="xsd:int"> ... <portType name="numberService"> <operation name="primeProcessor"> <input name="numRequest" message="tns:numRequest" /> <output name="numResponse" message="tns:numResponse" /> </operation> ... </portType> ... </definitions>
Example 11.12. Java Method with a List Type Parameter
public interface NumberService {
@XmlList
@WebResult(name = "outputData", targetNamespace = "", partName = "outputData")
@WebMethod
public int primeProcessor(
@WebParam(partName = "inputData", name = "primeList", targetNamespace = "...")
java.lang.Integer[] inputData
);
}In XML Schema, a union is a construct that allows you to describe a type whose data can be one of a number of simple types.
For example, you can define a type whose value is either the integer 1 or the string first. Unions
are mapped to Java Strings.
XML Schema unions are defined using a simpleType element. They contain at least one
union element that defines the member types of the union. The member types of the union are the
valid types of data that can be stored in an instance of the union. They are defined using the union
element's memberTypes attribute. The value of the memberTypes
attribute contains a list of one or more defined simple type names. Example 11.13
shows the definition of a union that can store either an integer or a string.
Example 11.13. Simple Union Type
<simpleType name="orderNumUnion"> <union memberTypes="xsd:string xsd:int" /> </simpleType>
In addition to specifying named types as a member type of a union, you can also define an anonymous simple type as a
member type of a union. This is done by adding the anonymous type definition inside of the union
element. Example 11.14 shows an example of a union containing an anonymous
member type that restricts the possible values of a valid integer to the range 1 through 10.
Example 11.14. Union with an Anonymous Member Type
<simpleType name="restrictedOrderNumUnion"> <union memberTypes="xsd:string"> <simpleType> <restriction base="xsd:int"> <minInclusive value="1" /> <maxInclusive value="10" /> </restriction> </simpleType> </union> </simpleType>
XML Schema union types are mapped to Java String objects. By default, Fuse Services Framework does not
validate the contents of the generated object. To have Fuse Services Framework validate the contents you will must configure the runtime to use
schema validation as described in Enforcing facets.
XML allows for simple type substitution between compatible types using the xsi:type
attribute. The default mapping of simple types to Java primitive types, however, does not fully support simple type substitution.
The runtime can handle basic simple type substitution, but information is lost. The code generators can be customized to
generate Java classes that facilitate lossless simple type substitution.
Because Java primitive types do not support type substitution, the default mapping of simple types to Java primitive types presents problems for supporting simple type substitution. The Java virtual machine will balk if an attempt is made to pass a short into a variable that expects an int even though the schema defining the types allows it.
To get around the limitations imposed by the Java type system, Fuse Services Framework allows for simple type substitution when the
value of the element's xsi:type attribute meets one of the following conditions:
It specifies a primitive type that is compatible with the element's schema type.
It specifies a type that derives by restriction from the element’s schema type.
It specifies a complex type that derives by extension from the element’s schema type.
When the runtime does the type substitution it does not retain any knowledge of the type specified in the element's
xsi:type attribute. If the type substitution is from a complex type to a simple type, only the value
directly related to the simple type is preserved. Any other elements and attributes added by extension are lost.
You can customize the generation of simple types to facilitate lossless support of simple type substitution in the following ways:
Set the globalBindings customization element's
mapSimpleTypeDef to true.
This instructs the code generator to create Java value classes for all named simple types defined in the global scope.
For more information see Generating Java Classes for Simple Types.
Add a javaType element to the globalBindings customization
element.
This instructs the code generators to map all instances of an XML Schema primitive type to s specific class of object.
For more information see Specifying the Java Class of an XML Schema Primitive.
Add a baseType customization element to the specific elements you want to
customize.
The baseType customization element allows you to specify the Java type generated to
represent a property. To ensure the best compatibility for simple type substitution, use
java.lang.Object as the base type.
For more information see Specifying the Base Type of an Element or an Attribute.
Complex types can contain multiple elements and they can have attributes. They are mapped into Java classes that can hold the data represented by the type definition. Typically, the mapping is to a bean with a set of properties representing the elements and the attributes of the content model..
XML Schema complex types define constructs containing more complex information than a simple type. The most simple complex types define an empty element with an attribute. More intricate complex types are made up of a collection of elements.
By default, an XML Schema complex type is mapped to a Java class, with a member variable to represent each element and attribute listed in the XML Schema definition. The class has setters and getters for each member variable.
XML Schema complex types are defined using the complexType element. The
complexType element wraps the rest of elements used to define the structure of the data. It can
appear either as the parent element of a named type definition, or as the child of an element
element anonymously defining the structure of the information stored in the element. When the
complexType element is used to define a named type, it requires the use of the
name attribute. The name attribute specifies a unique identifier
for referencing the type.
Complex type definitions that contain one or more elements have one of the child elements described in Table 12.1. These elements determine how the specified elements appear in an instance of the type.
Table 12.1. Elements for Defining How Elements Appear in a Complex Type
| Element | Description |
|---|---|
all | All of the elements defined as part of the complex type must appear in an instance of the type. However, they can appear in any order. |
choice | Only one of the elements defined as part of the complex type can appear in an instance of the type. |
sequence | All of the elements defined as part of the complex type must appear in an instance of the type, and they must also appear in the order specified in the type definition. |
![]() | Note |
|---|---|
If a complex type definition only uses attributes, you do not need one of the elements described in Table 12.1. |
After deciding how the elements will appear, you define the elements by adding one or more
element element children to the definition.
Example 12.1 shows a complex type definition in XML Schema.
Example 12.1. XML Schema Complex Type
<complexType name="sequence"> <sequence> <element name="name" type="xsd:string" /> <element name="street" type="xsd:short" /> <element name="city" type="xsd:string" /> <element name="state" type="xsd:string" /> <element name="zipCode" type="xsd:string" /> </sequence> </complexType>
XML Schema complex types are mapped to Java classes. Each element in the complex type definition is mapped to a member variable in the Java class. Getter and setter methods are also generated for each element in the complex type.
All generated Java classes are decorated with the @XmlType annotation. If the mapping is for a named complex type, the annotations name is set to the value of the complexType element's name attribute. If the complex type is defined as part of an element definition, the value of the @XmlType annotation's name property is the value of the element element's name attribute.
![]() | Note |
|---|---|
As described in Java mapping of elements with an in-line type, the generated class is decorated with the
|
To provide the runtime with guidelines indicating how the elements of the XML Schema complex type should be handled, the code generators alter the annotations used to decorate the class and its member variables.
All complex types are defined using the all element. They are annotated as
follows:
The @XmlType annotation's propOrder property is empty.
Each element is decorated with the @XmlElement annotation.
The @XmlElement annotation's required property is set to true.
Example 12.2 shows the mapping for an all complex type with two elements.
Example 12.2. Mapping of an All Complex Type
@XmlType(name = "all", propOrder = { }) public class All { @XmlElement(required = true) protected BigDecimal amount; @XmlElement(required = true) protected String type; public BigDecimal getAmount() { return amount; } public void setAmount(BigDecimal value) { this.amount = value; } public String getType() { return type; } public void setType(String value) { this.type = value; } }
Choice complex types are defined using the choice element. They are annotated
as follows:
The @XmlType annotation's propOrder property lists the names of the elements in the order they appear in the XML Schema definition.
None of the member variables are annotated.
Example 12.3 shows the mapping for a choice complex type with two elements.
Example 12.3. Mapping of a Choice Complex Type
@XmlType(name = "choice", propOrder = {
"address",
"floater"
})
public class Choice {
protected Sequence address;
protected Float floater;
public Sequence getAddress() {
return address;
}
public void setAddress(Sequence value) {
this.address = value;
}
public Float getFloater() {
return floater;
}
public void setFloater(Float value) {
this.floater = value;
}
}A sequence complex type is defined using the sequence element. It is annotated
as follows:
The @XmlType annotation's propOrder property lists the names of the elements in the order they appear in the XML Schema definition.
Each element is decorated with the @XmlElement annotation.
The @XmlElement annotation's required property is set to true.
Example 12.4 shows the mapping for the complex type defined in Example 12.1.
Example 12.4. Mapping of a Sequence Complex Type
@XmlType(name = "sequence", propOrder = { "name", "street", "city", "state", "zipCode" }) public class Sequence { @XmlElement(required = true) protected String name; protected short street; @XmlElement(required = true) protected String city; @XmlElement(required = true) protected String state; @XmlElement(required = true) protected String zipCode; public String getName() { return name; } public void setName(String value) { this.name = value; } public short getStreet() { return street; } public void setStreet(short value) { this.street = value; } public String getCity() { return city; } public void setCity(String value) { this.city = value; } public String getState() { return state; } public void setState(String value) { this.state = value; } public String getZipCode() { return zipCode; } public void setZipCode(String value) { this.zipCode = value; } }
Fuse Services Framework supports the use of attribute elements and
attributeGroup elements within the scope of a complexType element.
When defining structures for an XML document attribute declarations provide a means of adding information that is specified within
the tag, not the value that the tag contains. For example, when describing the XML element
<value currency="euro">410<\value> in XML Schema the currency
attribute is described using an attribute element as shown in
Example 12.5.
The attributeGroup element allows you to define a group of reusable attributes that can be
referenced by all complex types defined by the schema. For example, if you are defining a series of elements that all use the
attributes category and pubDate, you could define an attribute group
with these attributes and reference them in all the elements that use them. This is shown in
Example 12.7.
When describing data types for use in developing application logic, attributes whose use
attribute is set to either optional or required are treated as elements
of a structure. For each attribute declaration contained within a complex type description, an element is generated in the class for
the attribute, along with the appropriate getter and setter methods.
An XML Schema attribute element has one required attribute,
name, that is used to identify the attribute. It also has four optional attributes that are described in
Table 12.2.
Table 12.2. Optional Attributes Used to Define Attributes in XML Schema
| Attribute | Description |
|---|---|
use | Specifies if the attribute is required. Valid values are required, optional, or prohibited. optional is the default value. |
type | Specifies the type of value the attribute can take. If it is not used the schema type of the attribute must be defined in-line. |
default | Specifies a default value to use for the attribute. It is only used when the attribute element's use attribute is set to optional. |
fixed | Specifies a fixed value to use for the attribute. It is only used when the attribute element's use attribute is set to optional. |
Example 12.5 shows an attribute element defining an attribute, currency, whose value is a string.
Example 12.5. XML Schema Defining and Attribute
<element name="value"> <complexType> <xsd:simpleContent> <xsd:extension base="xsd:integer"> <xsd:attribute name="currency" type="xsd:string" use="required"/> </xsd:extension> </xsd:simpleContent> </xsd:complexType> </xsd:element>
If the type attribute is omitted from the attribute element, the format of the data must be described in-line. Example 12.6 shows an attribute element for an attribute, category, that can take the values autobiography, non-fiction, or fiction.
Example 12.6. Attribute with an In-Line Data Description
<attribute name="category" use="required"> <simpleType> <restriction base="xsd:string"> <enumeration value="autobiography"/> <enumeration value="non-fiction"/> <enumeration value="fiction"/> </restriction> </simpleType> </attribute>
Using an attribute group in a complex type definition is a two step process:
Define the attribute group.
An attribute group is defined using an attributeGroup element with a number of
attribute child elements. The attributeGroup requires a
name attribute that defines the string used to refer to the attribute group. The
attribute elements define the members of the attribute group and are specified as shown in
Defining an attribute in XML Schema. Example 12.7
shows the description of the attribute group catalogIndecies. The attribute group has two members:
category, which is optional, and pubDate, which is
required.
Example 12.7. Attribute Group Definition
<attributeGroup name="catalogIndices"> <attribute name="category" type="catagoryType" /> <attribute name="pubDate" type="dateTime" use="required" /> </attributeGroup>
Use the attribute group in the definition of a complex type.
You use attribute groups in complex type definitions by using the attributeGroup
element with the ref attribute. The value of the ref attribute is
the name given the attribute group that you want to use as part of the type definition. For example if you want to use the
attribute group catalogIndecies in the complex type dvdType, you would use
<attributeGroup ref="catalogIndecies" /> as shown in
Example 12.8.
Example 12.8. Complex Type with an Attribute Group
<complexType name="dvdType"> <sequence> <element name="title" type="xsd:string" /> <element name="director" type="xsd:string" /> <element name="numCopies" type="xsd:int" /> </sequence> <attributeGroup ref="catalogIndices" /> </complexType>
Attributes are mapped to Java in much the same way that member elements are mapped to Java. Required attributes and
optional attributes are mapped to member variables in the generated Java class. The member variables are decorated with the
@XmlAttribute annotation. If the attribute is required, the
@XmlAttribute annotation's required property is set to
true.
The complex type defined in Example 12.9 is mapped to the Java class shown in Example 12.10.
Example 12.9. techDoc Description
<complexType name="techDoc"> <all> <element name="product" type="xsd:string" /> <element name="version" type="xsd:short" /> </all> <attribute name="usefullness" type="xsd:float" use="optional" default="0.01" /> </complexType>
Example 12.10. techDoc Java Class
@XmlType(name = "techDoc", propOrder = { }) public class TechDoc { @XmlElement(required = true) protected String product; protected short version; @XmlAttribute protected Float usefullness; public String getProduct() { return product; } public void setProduct(String value) { this.product = value; } public short getVersion() { return version; } public void setVersion(short value) { this.version = value; } public float getUsefullness() { if (usefullness == null) { return 0.01F; } else { return usefullness; } } public void setUsefullness(Float value) { this.usefullness = value; } }
As shown in Example 12.10, the default attribute and the fixed attribute instruct the code generators to add code to the getter method generated for the attribute. This additional code ensures that the specified value is returned if no value is set.
![]() | Important |
|---|---|
The |
Attribute groups are mapped to Java as if the members of the group were explicitly used in the type definition. If the
attribute group has three members, and it is used in a complex type, the generated class for that type will include a member
variable, along with the getter and setter methods, for each member of the attribute group. For example, the complex type defined
in Example 12.8, Fuse Services Framework generates a class containing the member
variables category and pubDate to support the members of the attribute
group as shown in Example 12.11.
Example 12.11. dvdType Java Class
@XmlType(name = "dvdType", propOrder = { "title", "director", "numCopies" }) public class DvdType { @XmlElement(required = true) protected String title; @XmlElement(required = true) protected String director; protected int numCopies; @XmlAttribute protected CatagoryType category; @XmlAttribute(required = true) @XmlSchemaType(name = "dateTime") protected XMLGregorianCalendar pubDate; public String getTitle() { return title; } public void setTitle(String value) { this.title = value; } public String getDirector() { return director; } public void setDirector(String value) { this.director = value; } public int getNumCopies() { return numCopies; } public void setNumCopies(int value) { this.numCopies = value; } public CatagoryType getCatagory() { return catagory; } public void setCatagory(CatagoryType value) { this.catagory = value; } public XMLGregorianCalendar getPubDate() { return pubDate; } public void setPubDate(XMLGregorianCalendar value) { this.pubDate = value; } }
Fuse Services Framework supports derivation of a complex type from a simple type. A simple type has, by definition, neither sub-elements nor attributes. Hence, one of the main reasons for deriving a complex type from a simple type is to add attributes to the simple type.
There are two ways of deriving a complex type from a simple type:
Example 12.12 shows an example of a complex type, internationalPrice, derived by extension from the xsd:decimal primitive type to include a currency attribute.
Example 12.12. Deriving a Complex Type from a Simple Type by Extension
<complexType name="internationalPrice"> <simpleContent> <extension base="xsd:decimal"> <attribute name="currency" type="xsd:string"/> </extension> </simpleContent> </complexType>
The simpleContent element indicates that the new type does not contain any sub-elements. The extension element specifies that the new type extends xsd:decimal.
Example 12.13 shows an example of a complex type, idType, that is derived by restriction from xsd:string. The defined type restricts the possible values of xsd:stringto values that are ten characters in length. It also adds an attribute to the type.
Example 12.13. Deriving a Complex Type from a Simple Type by Restriction
<complexType name="idType"> <simpleContent> <restriction base="xsd:string"> <length value="10" /> <attribute name="expires" type="xsd:dateTime" /> </restriction> </simpleContent> </complexType>
As in Example 12.12 the simpleContent element
signals that the new type does not contain any children. This example uses a restriction element to
constrain the possible values used in the new type. The attribute element adds the element to the new
type.
A complex type derived from a simple type is mapped to a Java class that is decorated with the
@XmlType annotation. The generated class contains a member variable,
value, of the simple type from which the complex type is derived. The member variable is decorated with
the @XmlValue annotation. The class also has a getValue()
method and a setValue() method. In addition, the generated class has a member variable, and
the associated getter and setter methods, for each attribute that extends the simple type.
Example 12.14 shows the Java class generated for the idType type defined in Example 12.13.
Example 12.14. idType Java Class
@XmlType(name = "idType", propOrder = { "value" }) public class IdType { @XmlValue protected String value; @XmlAttribute @XmlSchemaType(name = "dateTime") protected XMLGregorianCalendar expires; public String getValue() { return value; } public void setValue(String value) { this.value = value; } public XMLGregorianCalendar getExpires() { return expires; } public void setExpires(XMLGregorianCalendar value) { this.expires = value; } }
Using XML Schema, you can derive new complex types by either extending or restricting other complex types using the
complexContent element. When generating the Java class to represent the derived complex type,
Fuse Services Framework extends the base type’s class. In this way, the generated Java code preserves the inheritance hierarchy intended in
the XML Schema.
You derive complex types from other complex types by using the complexContent element,
and either the extension element or the restriction element. The
complexContent element specifies that the included data description includes more than one field.
The extension element and the restriction element, which are children
of the complexContent element, specify the base type being modified to create the new type. The
base type is specified by the base attribute.
To extend a complex type use the extension element to define the additional elements and
attributes that make up the new type. All elements that are allowed in a complex type description are allowable as part of the new
type’s definition. For example, you can add an anonymous enumeration to the new type, or you can use the
choice element to specify that only one of the new fields can be valid at a time.
Example 12.15 shows an XML Schema fragment that defines two complex
types, widgetOrderInfo and widgetOrderBillInfo. widgetOrderBillInfo is derived by
extending widgetOrderInfo to include two new elements: orderNumber and
amtDue.
Example 12.15. Deriving a Complex Type by Extension
<complexType name="widgetOrderInfo"> <sequence> <element name="amount" type="xsd:int"/> <element name="order_date" type="xsd:dateTime"/> <element name="type" type="xsd1:widgetSize"/> <element name="shippingAddress" type="xsd1:Address"/> </sequence> <attribute name="rush" type="xsd:boolean" use="optional" /> </complexType> <complexType name="widgetOrderBillInfo"> <complexContent> <extension base="xsd1:widgetOrderInfo"> <sequence> <element name="amtDue" type="xsd:decimal"/> <element name="orderNumber" type="xsd:string"/> </sequence> <attribute name="paid" type="xsd:boolean" default="false" /> </extension> </complexContent> </complexType>
To restrict a complex type use the restriction element to limit the possible values of the base
type's elements or attributes. When restricting a complex type you must list all of the elements and attributes of the base type. For
each element you can add restrictive attributes to the definition. For example, you can add a
maxOccurs attribute to an element to limit the number of times it can occur. You can also use the
fixed attribute to force one or more of the elements to have predetermined values.
Example 12.16 shows an example of defining a complex type by restricting
another complex type. The restricted type, wallawallaAddress, can only be used for addresses in Walla Walla,
Washington because the values for the city element, the state
element, and the zipCode element are fixed.
Example 12.16. Defining a Complex Type by Restriction
<complexType name="Address"> <sequence> <element name="name" type="xsd:string"/> <element name="street" type="xsd:short" maxOccurs="3"/> <element name="city" type="xsd:string"/> <element name="state" type="xsd:string"/> <element name="zipCode" type="xsd:string"/> </sequence> </complexType> <complexType name="wallawallaAddress"> <complexContent> <restriction base="xsd1:Address"> <sequence> <element name="name" type="xsd:string"/> <element name="street" type="xsd:short" maxOccurs="3"/> <element name="city" type="xsd:string" fixed="WallaWalla"/> <element name="state" type="xsd:string" fixed="WA" /> <element name="zipCode" type="xsd:string" fixed="99362" /> </sequence> </restriction> </complexContent> </complexType>
As it does with all complex types, Fuse Services Framework generates a class to represent complex types derived from another complex type. The Java class generated for the derived complex type extends the Java class generated to support the base complex type. The base Java class is also modified to include the @XmlSeeAlso annotation. The base class' @XmlSeeAlso annotation lists all of the classes that extend the base class.
When the new complex type is derived by extension, the generated class will include member variables for all of the added elements and attributes. The new member variables will be generated according to the same mappings as all other elements.
When the new complex type is derived by restriction, the generated class will have no new member variables. The generated class will simply be a shell that does not provide any additional functionality. It is entirely up to you to ensure that the restrictions defined in the XML Schema are enforced.
For example, the schema in Example 12.15 results in the generation of two
Java classes: WidgetOrderInfo and WidgetBillOrderInfo.
WidgetOrderBillInfo extends WidgetOrderInfo because
widgetOrderBillInfo is derived by extension from widgetOrderInfo.
Example 12.17 shows the generated class for widgetOrderBillInfo.
Example 12.17. WidgetOrderBillInfo
@XmlType(name = "widgetOrderBillInfo", propOrder = { "amtDue", "orderNumber" }) public class WidgetOrderBillInfo extends WidgetOrderInfo { @XmlElement(required = true) protected BigDecimal amtDue; @XmlElement(required = true) protected String orderNumber; @XmlAttribute protected Boolean paid; public BigDecimal getAmtDue() { return amtDue; } public void setAmtDue(BigDecimal value) { this.amtDue = value; } public String getOrderNumber() { return orderNumber; } public void setOrderNumber(String value) { this.orderNumber = value; } public boolean isPaid() { if (paid == null) { return false; } else { return paid; } } public void setPaid(Boolean value) { this.paid = value; } }
XML Schema allows you to specify the occurrence constraints on four of the XML Schema elements that make up a complex type definition:
Complex types defined with the all element do not allow for multiple occurrences of the structure
defined by the all element. You can, however, make the structure defined by the
all element optional by setting its minOccurs attribute to
0.
By default, the results of a choice element can only appear once in an instance of a complex
type. You can change the number of times the element chosen to represent the structure defined by a
choice element is allowed to appear using its minOccurs attribute and
its mxOccurs attribute. Using these attributes you can specify that the choice type can occur zero to
an unlimited number of times in an instance of a complex type. The element chosen for the choice type does not need to be the same
for each occurrence of the type.
The minOccurs attribute specifies the minimum number of times the choice type must appear. Its value can be any positive integer. Setting the minOccurs attribute to 0 specifies that the choice type does not need to appear inside an instance of the complex type.
The maxOccurs attribute specifies the maximum number of times the choice type can appear. Its value can be any non-zero, positive integer or unbounded. Setting the maxOccurs attribute to unbounded specifies that the choice type can appear an infinite number of times.
Example 12.18 shows the definition of a choice type, ClubEvent, with choice occurrence constraints. The choice type overall can be repeated 0 to unbounded times.
Example 12.18. Choice Occurrence Constraints
<complexType name="ClubEvent"> <choice minOccurs="0" maxOccurs="unbounded"> <element name="MemberName" type="xsd:string"/> <element name="GuestName" type="xsd:string"/> </choice> </complexType>
Unlike single instance choice structures, XML Schema choice structures that can occur multiple times are mapped to a Java
class with a single member variable. This single member variable is a List<T> object that holds all
of the data for the multiple occurrences of the sequence. For example, if the sequence defined in
Example 12.18 occurred two times, then the list would have two
items.
The name of the Java class' member variable is derived by concatenating the names of the member elements. The element names are separated by Or and the first letter of the variable name is converted to lower case. For example, the member variable generated from Example 12.18 would be named memberNameOrGuestName.
The type of object stored in the list depends on the relationship between the types of the member elements. For example:
If the member elements are of the same type the generated list will contain JAXBElement<T> objects. The base type of the JAXBElement<T> objects is determined by the normal mapping of the member elements' type.
If the member elements are of different types and their Java representations implement a common interface, the list will contains objects of the common interface.
If the member elements are of different types and their Java representations extend a common base class, the list will contains objects of the common base class.
If none of the other conditions are met, the list will contain Object objects.
The generated Java class will only have a getter method for the member variable. The getter method returns a reference to the live list. Any modifications made to the returned list will effect the actual object.
The Java class is decorated with the @XmlType annotation. The annotation's
name property is set to the value of the name attribute from the parent
element of the XML Schema definition. The annotation's propOrder property contains the single member
variable representing the elements in the sequence.
The member variable representing the elements in the choice structure are decorated with the
@XmlElements annotation. The @XmlElements annotation
contains a comma separated list of @XmlElement annotations. The list has one
@XmlElement annotation for each member element defined in the XML Schema definition of the
type. The @XmlElement annotations in the list have their name
property set to the value of the XML Schema element element's name
attribute and their type property set to the Java class resulting from the mapping of the XML Schema
element element's type.
Example 12.19 shows the Java mapping for the XML Schema choice structure defined in Example 12.18.
Example 12.19. Java Representation of Choice Structure with an Occurrence Constraint
@XmlType(name = "ClubEvent", propOrder = { "memberNameOrGuestName" }) public class ClubEvent { @XmlElementRefs({ @XmlElementRef(name = "GuestName", type = JAXBElement.class), @XmlElementRef(name = "MemberName", type = JAXBElement.class) }) protected List<JAXBElement<String>> memberNameOrGuestName; public List<JAXBElement<String>> getMemberNameOrGuestName() { if (memberNameOrGuestName == null) { memberNameOrGuestName = new ArrayList<JAXBElement<String>>(); } return this.memberNameOrGuestName; } }
You can specify how many times a specific element in a complex type appears using the element element's minOccurs attribute and maxOccurs attribute. The default value for both attributes is 1.
When you set one of the complex type's member element's minOccurs attribute to 0, the @XmlElement annotation decorating the corresponding Java member variable is changed. Instead of having its required property set to true, the @XmlElement annotation's required property is set to false.
In XML Schema you can specify that an element must occur more than once in an instance of the type by setting the
element element's minOccurs attribute to a value greater than one.
However, the generated Java class will not support the XML Schema constraint. Fuse Services Framework generates the supporting Java member
variable as if the minOccurs attribute were not set.
When you want a member element to appear multiple times in an instance of a complex type, you set the element's
maxOccurs attribute to a value greater than 1. You can set the
maxOccurs attribute's value to unbounded to specify that the member
element can appear an unlimited number of times.
The code generators map a member element with the maxOccurs attribute set to a value
greater than 1 to a Java member variable that is a List<T> object. The base class of the list is
determined by mapping the element's type to Java. For XML Schema primitive types, the wrapper classes are used as described in
Wrapper classes. For example, if the member element is of type xsd:int
the generated member variable is a List<Integer> object.
By default, the contents of a sequence element can only appear once in an instance of a complex type. You can change the number of times the sequence of elements defined by a sequence element is allowed to appear using its minOccurs attribute and its maxOccurs attribute. Using these attributes you can specify that the sequence type can occur zero to an unlimited number of times in an instance of a complex type.
The minOccurs attribute specifies the minimum number of times the sequence must occur in an instance of the defined complex type. Its value can be any positive integer. Setting the minOccurs attribute to 0 specifies that the sequence does not need to appear inside an instance of the complex type.
The maxOccurs attribute specifies the upper limit for how many times the sequence can occur in an instance of the defined complex type. Its value can be any non-zero, positive integer or unbounded. Setting the maxOccurs attribute to unbounded specifies that the sequence can appear an infinite number of times.
Example 12.20 shows the definition of a sequence type, CultureInfo, with sequence occurrence constraints. The sequence can be repeated 0 to 2 times.
Example 12.20. Sequence with Occurrence Constraints
<complexType name="CultureInfo"> <sequence minOccurs="0" maxOccurs="2"> <element name="Name" type="string"/> <element name="Lcid" type="int"/> </sequence> </complexType>
Unlike single instance sequences, XML Schema sequences that can occur multiple times are mapped to a Java class with a
single member variable. This single member variable is a List<T> object that holds all of the data
for the multiple occurrences of the sequence. For example, if the sequence defined in
Example 12.20 occurred two times, then the list would have four
items.
The name of the Java class' member variable is derived by concatenating the names of the member elements. The element
names are separated by And and the first letter of the variable name is converted to lower case. For example,
the member variable generated from Example 12.20 is named
nameAndLcid.
The type of object stored in the list depends on the relationship between the types of the member elements. For example:
If the member elements are of the same type the generated list will contain
JAXBElement<T> objects. The base type of the
JAXBElement<T> objects is determined by the normal mapping of the member elements'
type.
If the member elements are of different types and their Java representations implement a common interface, the list will contains objects of the common interface.
If the member elements are of different types and their Java representations extend a common base class, the list will contain objects of the common base class.
If none of the other conditions are met, the list will contain Object objects.
The generated Java class only has a getter method for the member variable. The getter method returns a reference to the live list. Any modifications made to the returned list effects the actual object.
The Java class is decorated with the @XmlType annotation. The annotation's
name property is set to the value of the name attribute from the parent
element of the XML Schema definition. The annotation's propOrder property contains the single member
variable representing the elements in the sequence.
The member variable representing the elements in the sequence are decorated with the
@XmlElements annotation. The @XmlElements annotation
contains a comma separated list of @XmlElement annotations. The list has one
@XmlElement annotation for each member element defined in the XML Schema definition of
the type. The @XmlElement annotations in the list have their name
property set to the value of the XML Schema element element's
name attribute and their type property set to the Java class resulting from
the mapping of the XML Schema element element's type.
Example 12.21 shows the Java mapping for the XML Schema sequence defined in Example 12.20.
Example 12.21. Java Representation of Sequence with an Occurrence Constraint
@XmlType(name = "CultureInfo", propOrder = { "nameAndLcid" }) public class CultureInfo { @XmlElements({ @XmlElement(name = "Name", type = String.class), @XmlElement(name = "Lcid", type = Integer.class) }) protected List<Serializable> nameAndLcid; public List<Serializable> getNameAndLcid() { if (nameAndLcid == null) { nameAndLcid = new ArrayList<Serializable>(); } return this.nameAndLcid; } }
XML Schema model groups are convenient shortcuts that allows you to reference a group of elements from a
user-defined complex type.For example, you can define a group of elements that are common to several types in your application
and then reference the group repeatedly. Model groups are defined using the group element, and
are similar to complex type definitions. The mapping of model groups to Java is also similar to the mapping for complex
types.
You define a model group in XML Schema using the group element with the
name attribute. The value of the name attribute is a string that is
used to refer to the group throughout the schema. The group element, like the
complexType element, can have the sequence element, the
all element, or the choice element as its immediate child.
Inside the child element, you define the members of the group using element elements. For
each member of the group, specify one element element. Group members can use any of the
standard attributes for the element element including minOccurs and
maxOccurs. So, if your group has three elements and one of them can occur up to three times, you
define a group with three element elements, one of which uses
maxOccurs="3". Example 12.22 shows a model group with three elements.
Example 12.22. XML Schema Model Group
<group name="passenger"> <sequence> <element name="name" type="xsd:string" /> <element name="clubNum" type="xsd:long" /> <element name="seatPref" type="xsd:string" maxOccurs="3" /> </sequence> </group>
Once a model group has been defined, it can be used as part of a complex type definition. To use a model group in a
complex type definition, use the group element with the ref attribute.
The value of the ref attribute is the name given to the group when it was defined. For example, to
use the group defined in Example 12.22 you use
<group ref="tns:passenger" /> as shown in
Example 12.23.
Example 12.23. Complex Type with a Model Group
<complexType name="reservation"> <sequence> <group ref="tns:passenger" /> <element name="origin" type="xsd:string" /> <element name="destination" type="xsd:string" /> <element name="fltNum" type="xsd:long" /> </sequence> </complexType>
When a model group is used in a type definition, the group becomes a member of the type. So an instance of
reservation has four member elements. The first element is the passenger element
and it contains the member elements defined by the group shown in
Example 12.22. An example of an instance of reservation is
shown in Example 12.24.
Example 12.24. Instance of a Type with a Model Group
<reservation>
<passenger>
<name>A. Smart</name>
<clubNum>99</clubNum>
<seatPref>isle1</seatPref>
</passenger>
<origin>LAX</origin>
<destination>FRA</destination>
<fltNum>34567</fltNum>
</reservation>By default, a model group is only mapped to Java artifacts when it is included in a complex type definition. When generating code for a complex type that includes a model group, Fuse Services Framework simply includes the member variables for the model group into the Java class generated for the type. The member variables representing the model group are annotated based on the definitions of the model group.
Example 12.25 shows the Java class generated for the complex type defined in Example 12.23.
Example 12.25. Type with a Group
@XmlType(name = "reservation", propOrder = { "name", "clubNum", "seatPref", "origin", "destination", "fltNum" }) public class Reservation { @XmlElement(required = true) protected String name; protected long clubNum; @XmlElement(required = true) protected List<String> seatPref; @XmlElement(required = true) protected String origin; @XmlElement(required = true) protected String destination; protected long fltNum; public String getName() { return name; } public void setName(String value) { this.name = value; } public long getClubNum() { return clubNum; } public void setClubNum(long value) { this.clubNum = value; } public List<String> getSeatPref() { if (seatPref == null) { seatPref = new ArrayList<String>(); } return this.seatPref; } public String getOrigin() { return origin; } public void setOrigin(String value) { this.origin = value; } public String getDestination() { return destination; } public void setDestination(String value) { this.destination = value; } public long getFltNum() { return fltNum; } public void setFltNum(long value) { this.fltNum = value; }
You can specify that the model group appears more than once by setting the group
element's maxOccurs attribute to a value greater than one. To allow for multiple occurrences of
the model group Fuse Services Framework maps the model group to a List<T> object. The
List<T> object is generated following the rules for the group's first child:
If the group is defined using a sequence element see
Occurrence Constraints on Sequences.
If the group is defined using a choice element see
Occurrence Constraints on the Choice Element.
There are instances when a schema author wants to defer binding elements or attributes to a defined type. For these cases, XML Schema provides three mechanisms for specifying wild card place holders. These are all mapped to Java in ways that preserve their XML Schema functionality.
The XML Schema any element is used to create a wild card place holder in complex type
definitions. When an XML element is instantiated for an XML Schema any element, it can be any valid
XML element. The any element does not place any restrictions on either the content or the name of
the instantiated XML element.
For example, given the complex type defined in Example 13.1 you can instantiate either of the XML elements shown in Example 13.2.
Example 13.1. XML Schema Type Defined with an Any Element
<element name="FlyBoy"> <complexType> <sequence> <any /> <element name="rank" type="xsd:int" /> </sequence> </complexType> </element>
Example 13.2. XML Document with an Any Element
<FlyBoy> <learJet>CL-215</learJet> <rank>2</rank> </element> <FlyBoy> <viper>Mark II</viper> <rank>1</rank> </element>
XML Schema any elements are mapped to either a Java Object object or a Java org.w3c.dom.Element object.
The any element can be used when defining sequence complex types and choice complex
types. In most cases, the any element is an empty element. It can, however, take an
annotation element as a child.
Table 13.1 describes the any element's
attributes.
Table 13.1. Attributes of the XML Schema Any Element
| Attribute | Description |
|---|---|
namespace |
Specifies the namespace of the elements that can be used to instantiate the element in an XML document. The valid values are:
|
maxOccurs | Specifies the maximum number of times an instance of the element can appear in the parent element. The default value is 1. To specify that an instance of the element can appear an unlimited number of times, you can set the attribute's value to unbounded. |
minOccurs | Specifies the minimum number of times an instance of the element can appear in the parent element. The default value is 1. |
processContents |
Specifies how the element used to instantiate the any element should be validated. Valid values are:
|
Example 13.3 shows a complex type defined with an any element
Example 13.3. Complex Type Defined with an Any Element
<complexType name="surprisePackage"> <sequence> <any processContents="lax" /> <element name="to" type="xsd:string" /> <element name="from" type="xsd:string" /> </sequence> </complexType>
XML Schema any elements result in the creation of a Java property named
any. The property has associated getter and setter methods. The type of the resulting property depends on the
value of the element's processContents attribute. If the any element's
processContents attribute is set to skip, the element is mapped to a
org.w3c.dom.Element object. For all other values of the
processContents attribute an any element is mapped to a Java
Object object.
The generated property is decorated with the @XmlAnyElement annotation. This
annotation has an optional lax property that instructs the runtime what to do when marshaling the data. Its
default value is false which instructs the runtime to automatically marshal the data into a
org.w3c.dom.Element object. Setting lax to true instructs
the runtime to attempt to marshal the data into JAXB types. When the any element's
processContents attribute is set to skip, the
lax property is set to its default value. For all other values of the
processContents attribute, lax is set to true.
Example 13.4 shows how the complex type defined in Example 13.3 is mapped to a Java class.
Example 13.4. Java Class with an Any Element
public class SurprisePackage {
@XmlAnyElement(lax = true)
protected Object any;
@XmlElement(required = true)
protected String to;
@XmlElement(required = true)
protected String from;
public Object getAny() {
return any;
}
public void setAny(Object value) {
this.any = value;
}
public String getTo() {
return to;
}
public void setTo(String value) {
this.to = value;
}
public String getFrom() {
return from;
}
public void setFrom(String value) {
this.from = value;
}
}If the Java property for an any element has its lax set to
false, or the property is not specified, the runtime makes no attempt to parse the XML data into JAXB objects.
The data is always stored in a DOM Element object.
If the Java property for an any element has its lax set to
true, the runtime attempts to marshal the XML data into the appropriate JAXB objects. The runtime attempts to
identify the proper JAXB classes using the following procedure:
It checks the element tag of the XML element against the list of elements known to the runtime. If it finds a match, the runtime marshals the XML data into the proper JAXB class for the element.
It checks the XML element's xsi:type attribute. If it finds a match, the runtime marshals the
XML element into the proper JAXB class for that type.
If it cannot find a match it marshals the XML data into a DOM Element object.
Usually an application's runtime knows about all of the types generated from the schema's included in its contract. This
includes the types defined in the contract's wsdl:types element, any data types added to the contract
through inclusion, and any types added to the contract through importing other schemas. You can also make the runtime aware of
additional types using the @XmlSeeAlso annotation which is described in
Adding Classes to the Runtime Marshaller.
If the Java property for an any element has its lax set to
false, or the property is not specified, the runtime will only accept DOM Element
objects. Attempting to use any other type of object will result in a marshalling error.
If the Java property for an any element has its lax set to
true, the runtime uses its internal map between Java data types and the XML Schema constructs they represent
to determine the XML structure to write to the wire. If the runtime knows the class and can map it to an XML Schema construct, it
writes out the data and inserts an xsi:type attribute to identify the type of data the element
contains.
If the runtime cannot map the Java object to a known XML Schema construct, it will throw a marshaling exception. You can
add types to the runtime's map using the @XmlSeeAlso annotation which is described in
Adding Classes to the Runtime Marshaller.
The XML Schema type xsd:anyType is the root type for all XML Schema types. All of the primitives are derivatives of this type, as are all user defined complex types. As a result, elements defined as being of xsd:anyType can contain data in the form of any of the XML Schema primitives as well as any complex type defined in a schema document.
In Java the closest matching type is the Object class. It is the class from which all other Java
classes are sub-typed.
You use the xsd:anyType type as you would any other XML Schema complex type. It can be used as the value of an element element's type element. It can also be used as the base type from which other types are defined.
Example 13.5 shows an example of a complex type that contains an element of type xsd:anyType.
Example 13.5. Complex Type with a Wild Card Element
<complexType name="wildStar"> <sequence> <element name="name" type="xsd:string" /> <element name="ship" type="xsd:anyType" /> </sequence> </complexType>
Elements that are of type xsd:anyType are mapped to Object objects. Example 13.6 shows the mapping of Example 13.5 to a Java class.
Example 13.6. Java Representation of a Wild Card Element
public class WildStar {
@XmlElement(required = true)
protected String name;
@XmlElement(required = true)
protected Object ship;
public String getName() {
return name;
}
public void setName(String value) {
this.name = value;
}
public Object getShip() {
return ship;
}
public void setShip(Object value) {
this.ship = value;
}
}This mapping allows you to place any data into the property representing the wild card element. The Fuse Services Framework runtime handles the marshaling and unmarshaling of the data into usable Java representation.
When Fuse Services Framework marshals XML data into Java types, it attempts to marshal anyType elements into known
JAXB objects. To determine if it is possible to marshal an anyType element into a JAXB generated object, the runtime
inspects the element's xsi:type attribute to determine the actual type used to construct the data in the
element. If the xsi:type attribute is not present, the runtime attempts to identify the element's actual
data type by introspection. If the element's actual data type is determined to be one of the types known by the application's JAXB
context, the element is marshaled into a JAXB object of the proper type.
If the runtime cannot determine the actual data type of the element, or the actual data type of the element is not a known type,
the runtime marshals the content into a org.w3c.dom.Element object. You will then need to work with the
element's content using the DOM APis.
An application's runtime usually knows about all of the types generated from the schema's included in its contract. This
includes the types defined in the contract's wsdl:types element, any data types added to the
contract through inclusion, and any types added to the contract through importing other schema documents. You can also make the
runtime aware of additional types using the @XmlSeeAlso annotation which is described in
Adding Classes to the Runtime Marshaller.
When Fuse Services Framework unmarshals Java types into XML data, it uses an internal map between Java data types and the XML Schema
constructs they represent to determine the XML structure to write to the wire. If the runtime knows the class and can map the class to
an XML Schema construct, it writes out the data and inserts an xsi:type attribute to identify the type of
data the element contains. If the data is stored in a org.w3c.dom.Element object, the runtime writes
the XML structure represented by the object but it does not include an xsi:type attribute.
If the runtime cannot map the Java object to a known XML Schema construct, it throws a marshaling exception. You can add
types to the runtime's map using the @XmlSeeAlso annotation which is described in
Adding Classes to the Runtime Marshaller.
XML Schema has a mechanism that allows you to leave a place holder for an arbitrary attribute in a complex type definition. Using this mechanism, you can define a complex type that can have any attribute. For example, you can create a type that defines the elements <robot name="epsilon" />, <robot age="10000" />, or <robot type="weevil" /> without specifying the three attributes. This can be particularly useful when flexibility in your data is required.
Undeclared attributes are defined in XML Schema using the anyAttribute element. It can be
used wherever an attribute element can be used. The anyAttribute element has no attributes, as
shown in Example 13.7.
Example 13.7. Complex Type with an Undeclared Attribute
<complexType name="arbitter"> <sequence> <element name="name" type="xsd:string" /> <element name="rate" type="xsd:float" /> </sequence> <anyAttribute /> </complexType>
The defined type, arbitter, has two elements and can have one attribute of any type. The elements three elements shown in Example 13.8 can all be generated from the complex type arbitter.
Example 13.8. Examples of Elements Defined with a Wild Card Attribute
<officer rank="12"><name>...</name><rate>...</rate></officer> <lawyer type="divorce"><name>...</name><rate>...</rate></lawyer> <judge><name>...</name><rate>...</rate></judge>
When a complex type containing an anyAttribute element is mapped to Java, the code
generator adds a member called otherAttributes to the generated class.
otherAttributes is of type java.util.Map<QName, String> and it has a
getter method that returns a live instance of the map. Because the map returned from the getter is live, any modifications to the
map are automatically applied. Example 13.9 shows the class generated for the complex
type defined in Example 13.7.
Example 13.9. Class for a Complex Type with an Undeclared Attribute
public class Arbitter {
@XmlElement(required = true)
protected String name;
protected float rate;
@XmlAnyAttribute
private Map<QName, String> otherAttributes = new HashMap<QName, String>();
public String getName() {
return name;
}
public void setName(String value) {
this.name = value;
}
public float getRate() {
return rate;
}
public void setRate(float value) {
this.rate = value;
}
public Map<QName, String> getOtherAttributes() {
return otherAttributes;
}
}The otherAttributes member of the generated class expects to be populated with a
Map object. The map is keyed using QNames. Once you get the map ,
you can access any attributes set on the object and set new attributes on the object.
Example 13.10 shows sample code for working with undeclared attributes.
The code in Example 13.10 does the following:
A substitution group is a feature of XML schema that allows you to specify elements that can replace another element in documents generated from that schema. The replaceable element is called the head element and must be defined in the schema’s global scope. The elements of the substitution group must be of the same type as the head element or a type that is derived from the head element’s type.
In essence, a substitution group allows you to build a collection of elements that can be specified using a generic element. For example, if you are building an ordering system for a company that sells three types of widgets you might define a generic widget element that contains a set of common data for all three widget types. Then you can define a substitution group that contains a more specific set of data for each type of widget. In your contract you can then specify the generic widget element as a message part instead of defining a specific ordering operation for each type of widget. When the actual message is built, the message can contain any of the elements of the substitution group.
Substitution groups are defined using the substitutionGroup attribute of the XML Schema
element element. The value of the substitutionGroup attribute is
the name of the element that the element being defined replaces. For example, if your head element is
widget, adding the attribute substitutionGroup="widget" to an
element named woodWidget specifies that anywhere a widget
element is used, you can substitute a woodWidget element. This is shown in
Example 14.1.
Example 14.1. Using a Substitution Group
<element name="widget" type="xsd:string" /> <element name="woodWidget" type="xsd:string" substitutionGroup="widget" />
The elements of a substitution group must be of the same type as the head element or of a type derived from the head element’s type. For example, if the head element is of type xsd:int all members of the substitution group must be of type xsd:int or of a type derived from xsd:int. You can also define a substitution group similar to the one shown in Example 14.2 where the elements of the substitution group are of types derived from the head element’s type.
Example 14.2. Substitution Group with Complex Types
<complexType name="widgetType"> <sequence> <element name="shape" type="xsd:string" /> <element name="color" type="xsd:string" /> </sequence> </complexType> <complexType name="woodWidgetType"> <complexContent> <extension base="widgetType"> <sequence> <element name="woodType" type="xsd:string" /> </sequence> </extension> </complexContent> </complexType> <complexType name="plasticWidgetType"> <complexContent> <extension base="widgetType"> <sequence> <element name="moldProcess" type="xsd:string" /> </sequence> </extension> </complexContent> </complexType> <element name="widget" type="widgetType" /> <element name="woodWidget" type="woodWidgetType" substitutionGroup="widget" /> <element name="plasticWidget" type="plasticWidgetType" substitutionGroup="widget" /> <complexType name="partType"> <sequence> <element ref="widget" /> </sequence> </complexType> <element name="part" type="partType" />
The head element of the substitution group, widget, is defined as being of type
widgetType. Each element of the substitution group extends widgetType to include data that is
specific to ordering that type of widget.
Based on the schema in Example 14.2, the part
elements in Example 14.3 are valid.
Example 14.3. XML Document using a Substitution Group
<part>
<widget>
<shape>round</shape>
<color>blue</color>
</widget>
</part>
<part>
<plasticWidget>
<shape>round</shape>
<color>blue</color>
<moldProcess>sandCast</moldProcess>
</plasticWidget>
</part>
<part>
<woodWidget>
<shape>round</shape>
<color>blue</color>
<woodType>elm</woodType>
</woodWidget>
</part>You can define an abstract head element that can never appear in a document produced using your schema. Abstract head elements are similar to abstract classes in Java because they are used as the basis for defining more specific implementations of a generic class. Abstract heads also prevent the use of the generic element in the final product.
You declare an abstract head element by setting the abstract attribute of an
element element to true, as shown in
Example 14.4. Using this schema, a valid review element can
contain either a positiveComment element or a negativeComment
element, but cannot contain a comment element.
Example 14.4. Abstract Head Definition
<element name="comment" type="xsd:string" abstract="true" /> <element name="positiveComment" type="xsd:string" substitutionGroup="comment" /> <element name="negtiveComment" type="xsd:string" substitutionGroup="comment" /> <element name="review"> <complexContent> <all> <element name="custName" type="xsd:string" /> <element name="impression" ref="comment" /> </all> </complexContent> </element>
Fuse Services Framework, as specified in the JAXB specification, supports substitution groups using Java's native class hierarchy in
combination with the ability of the JAXBElement class' support for wildcard definitions. Because the
members of a substitution group must all share a common base type, the classes generated to support the elements' types also
share a common base type. In addition, Fuse Services Framework maps instances of the head element to
JAXBElement<? extends T> properties.
The object factory generated to support a package containing a substitution group has methods for each of the elements in
the substitution group. For each of the members of the substitution group, except for the head element, the
@XmlElementDecl annotation decorating the object factory method includes two additional
properties, as described in Table 14.1.
Table 14.1. Properties for Declaring a JAXB Element is a Member of a Substitution Group
| Property | Description |
|---|---|
| substitutionHeadNamespace | Specifies the namespace where the head element is defined. |
| substitutionHeadName | Specifies the value of the head element's name attribute. |
The object factory method for the head element of the substitution group's
@XmlElementDecl contains only the default namespace property and
the default name property.
In addition to the element instantiation methods, the object factory contains a method for instantiating an object representing the head element. If the members of the substitution group are all of complex types, the object factory also contains methods for instantiating instances of each complex type used.
Example 14.5 shows the object factory method for the substitution group defined in Example 14.2.
Example 14.5. Object Factory Method for a Substitution Group
public class ObjectFactory {
private final static QName _Widget_QNAME = new QName(...);
private final static QName _PlasticWidget_QNAME = new QName(...);
private final static QName _WoodWidget_QNAME = new QName(...);
public ObjectFactory() {
}
public WidgetType createWidgetType() {
return new WidgetType();
}
public PlasticWidgetType createPlasticWidgetType() {
return new PlasticWidgetType();
}
public WoodWidgetType createWoodWidgetType() {
return new WoodWidgetType();
}
@XmlElementDecl(namespace="...", name = "widget")
public JAXBElement<WidgetType> createWidget(WidgetType value) {
return new JAXBElement<WidgetType>(_Widget_QNAME, WidgetType.class, null, value);
}
@XmlElementDecl(namespace = "...", name = "plasticWidget", substitutionHeadNamespace = "...", substitutionHeadName = "widget")
public JAXBElement<PlasticWidgetType> createPlasticWidget(PlasticWidgetType value) {
return new JAXBElement<PlasticWidgetType>(_PlasticWidget_QNAME, PlasticWidgetType.class, null, value);
}
@XmlElementDecl(namespace = "...", name = "woodWidget", substitutionHeadNamespace = "...", substitutionHeadName = "widget")
public JAXBElement<WoodWidgetType> createWoodWidget(WoodWidgetType value) {
return new JAXBElement<WoodWidgetType>(_WoodWidget_QNAME, WoodWidgetType.class, null, value);
}
}If the head element of a substitution group is used as a message part in one of an operation's messages, the resulting method
parameter will be an object of the class generated to support that element. It will not necessarily be an instance of the
JAXBElement<? extends T> class. The runtime relies on Java's native type hierarchy to support the
type substitution, and Java will catch any attempts to use unsupported types.
To ensure that the runtime knows all of the classes needed to support the element substitution, the SEI is decorated
with the @XmlSeeAlso annotation. This annotation specifies a list of classes required by the
runtime for marshalling. Fore more information on using the @XmlSeeAlso annotation see
Adding Classes to the Runtime Marshaller.
Example 14.7 shows the SEI generated for the interface shown in Example 14.6. The interface uses the substitution group defined in Example 14.2.
Example 14.6. WSDL Interface Using a Substitution Group
<message name="widgetMessage"> <part name="widgetPart" element="xsd1:widget" /> </message> <message name="numWidgets"> <part name="numInventory" type="xsd:int" /> </message> <message name="badSize"> <part name="numInventory" type="xsd:int" /> </message> <portType name="orderWidgets"> <operation name="placeWidgetOrder"> <input message="tns:widgetOrder" name="order" /> <output message="tns:widgetOrderBill" name="bill" /> <fault message="tns:badSize" name="sizeFault" /> </operation> <operation name="checkWidgets"> <input message="tns:widgetMessage" name="request" /> <output message="tns:numWidgets" name="response" /> </operation> </portType>
Example 14.7. Generated Interface Using a Substitution Group
@WebService(targetNamespace = "...", name = "orderWidgets") @XmlSeeAlso({com.widgetvendor.types.widgettypes.ObjectFactory.class}) public interface OrderWidgets { @SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE) @WebResult(name = "numInventory", targetNamespace = "", partName = "numInventory") @WebMethod public int checkWidgets( @WebParam(partName = "widgetPart", name = "widget", targetNamespace = "...") com.widgetvendor.types.widgettypes.WidgetType widgetPart ); }
![]() | Tip |
|---|---|
The SEI shown in Example 14.7 lists the object factory in the |
When the head element of a substitution group is used as an element in a complex type, the code generator maps the element to a JAXBElement<? extends T> property. It does not map it to a property containing an instance of the generated class generated to support the substitution group.
For example, the complex type defined in Example 14.8 results in the Java class shown in Example 14.9. The complex type uses the substitution group defined in Example 14.2.
Example 14.8. Complex Type Using a Substitution Group
<complexType name="widgetOrderInfo"> <sequence> <element name="amount" type="xsd:int"/> <element ref="xsd1:widget"/> </sequence> </complexType>
Example 14.9. Java Class for a Complex Type Using a Substitution Group
@XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "widgetOrderInfo", propOrder = {"amount","widget",}) public class WidgetOrderInfo { protected int amount; @XmlElementRef(name = "widget", namespace = "...", type = JAXBElement.class) protected JAXBElement<? extends WidgetType> widget; public int getAmount() { return amount; } public void setAmount(int value) { this.amount = value; } public JAXBElement<? extends WidgetType> getWidget() { return widget; } public void setWidget(JAXBElement<? extends WidgetType> value) { this.widget = ((JAXBElement<? extends WidgetType> ) value); } }
How you work with a substitution group depends on whether the code generator mapped the group to a straight Java class or
to a JAXBElement<? extends T> class. When the element is simply mapped to an object of the
generated value class, you work with the object the same way you work with other Java objects that are part of a type hierarchy. You
can substitute any of the subclasses for the parent class. You can inspect the object to determine its exact class, and cast it
appropriately.
![]() | Tip |
|---|---|
The JAXB specification recommends that you use the object factory methods for instantiating objects of the generated classes. |
When the code generators create a JAXBElement<? extends T> object to hold instances of a
substitution group, you must wrap the element's value in a JAXBElement<? extends T> object. The
best method to do this is to use the element creation methods provided by the object factory. They provide an easy means for
creating an element based on its value.
Example 14.10 shows code for setting an instance of a substitution group.
Example 14.10. Setting a Member of a Substitution Group
ObjectFactory of = new ObjectFactory();PlasticWidgetType pWidget = of.createPlasticWidgetType();
pWidget.setShape = "round'; pWidget.setColor = "green"; pWidget.setMoldProcess = "injection"; JAXBElement<PlasticWidgetType> widget = of.createPlasticWidget(pWidget);
WidgetOrderInfo order = of.createWidgetOrderInfo();
order.setWidget(widget);
The code in Example 14.10 does the following:
Instantiates an object factory. | |
Instantiates a | |
Instantiates a | |
Instantiates a | |
Sets the |
The object factory methods do not help when extracting the element's value from a
JAXBElement<? extends T> object. You must to use the
JAXBElement<? extends T> object's getValue() method. The
following options determine the type of object returned by the getValue() method:
Use the isInstance() method of all the possible classes to determine the class of the element's value object.
Use the JAXBElement<? extends T> object's getName()
method to determine the element's name.
The getName() method returns a QName. Using the local name of the element, you
can determine the proper class for the value object.
Use the JAXBElement<? extends T> object's getDeclaredType() method to determine the class of the value object.
The getDeclaredType() method returns the Class object of
the element's value object.
![]() | Warning |
|---|---|
There is a possibility that the |
Example 14.11 shows code retrieving the value from a substitution group. To determine
the proper class of the element's value object the example uses the element's getName()
method.
Example 14.11. Getting the Value of a Member of the Substitution Group
String elementName = order.getWidget().getName().getLocalPart();
if (elementName.equals("woodWidget")
{
WoodWidgetType widget=order.getWidget().getValue();
}
else if (elementName.equals("plasticWidget")
{
PlasticWidgetType widget=order.getWidget().getValue();
}
else
{
WidgetType widget=order.getWidget().getValue();
}This section shows an example of substitution groups being used in Fuse Services Framework to solve a real world application. A service and consumer are developed using the widget substitution group defined in Example 14.2. The service offers two operations: checkWidgets and placeWidgetOrder. Example 14.12 shows the interface for the ordering service.
Example 14.12. Widget Ordering Interface
<message name="widgetOrder"> <part name="widgetOrderForm" type="xsd1:widgetOrderInfo"/> </message> <message name="widgetOrderBill"> <part name="widgetOrderConformation" type="xsd1:widgetOrderBillInfo"/> </message> <message name="widgetMessage"> <part name="widgetPart" element="xsd1:widget" /> </message> <message name="numWidgets"> <part name="numInventory" type="xsd:int" /> </message> <portType name="orderWidgets"> <operation name="placeWidgetOrder"> <input message="tns:widgetOrder" name="order"/> <output message="tns:widgetOrderBill" name="bill"/> </operation> <operation name="checkWidgets"> <input message="tns:widgetMessage" name="request" /> <output message="tns:numWidgets" name="response" /> </operation> </portType>
Example 14.13 shows the generated Java SEI for the interface.
Example 14.13. Widget Ordering SEI
@WebService(targetNamespace = "http://widgetVendor.com/widgetOrderForm", name = "orderWidgets") @XmlSeeAlso({com.widgetvendor.types.widgettypes.ObjectFactory.class}) public interface OrderWidgets { @SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE) @WebResult(name = "numInventory", targetNamespace = "", partName = "numInventory") @WebMethod public int checkWidgets( @WebParam(partName = "widgetPart", name = "widget", targetNamespace = "http://widgetVendor.com/types/widgetTypes") com.widgetvendor.types.widgettypes.WidgetType widgetPart ); @SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE) @WebResult(name = "widgetOrderConformation", targetNamespace = "", partName = "widgetOrderConformation") @WebMethod public com.widgetvendor.types.widgettypes.WidgetOrderBillInfo placeWidgetOrder( @WebParam(partName = "widgetOrderForm", name = "widgetOrderForm", targetNamespace = "") com.widgetvendor.types.widgettypes.WidgetOrderInfo widgetOrderForm ) throws BadSize; }
![]() | Note |
|---|---|
Because the example only demonstrates the use of substitution groups, some of the business logic is not shown. |
checkWidgets is a simple operation that has a parameter that is the head member of a
substitution group. This operation demonstrates how to deal with individual parameters that are members of a substitution group.
The consumer must ensure that the parameter is a valid member of the substitution group. The service must properly determine
which member of the substitution group was sent in the request.
The generated method signature uses the Java class supporting the type of the substitution group's head element. Because the member elements of a substitution group are either of the same type as the head element or of a type derived from the head element's type, the Java classes generated to support the members of the substitution group inherit from the Java class generated to support the head element. Java's type hierarchy natively supports using subclasses in place of the parent class.
Because of how Fuse Services Framework generates the types for a substitution group and Java's type hierarchy, the client can invoke
checkWidgets() without using any special code. When developing the logic to invoke
checkWidgets() you can pass in an object of one of the classes generated to support the widget
substitution group.
Example 14.14 shows a consumer invoking
checkWidgets().
Example 14.14. Consumer Invoking checkWidgets()
System.out.println("What type of widgets do you want to order?");
System.out.println("1 - Normal");
System.out.println("2 - Wood");
System.out.println("3 - Plastic");
System.out.println("Selection [1-3]");
String selection = reader.readLine();
String trimmed = selection.trim();
char widgetType = trimmed.charAt(0);
switch (widgetType)
{
case '1':
{
WidgetType widget = new WidgetType();
...
break;
}
case '2':
{
WoodWidgetType widget = new WoodWidgetType();
...
break;
}
case '3':
{
PlasticWidgetType widget = new PlasticWidgetType();
...
break;
}
default :
System.out.println("Invaid Widget Selection!!");
}
proxy.checkWidgets(widgets);The service's implementation of checkWidgets() gets a widget description as a
WidgetType object, checks the inventory of widgets, and returns the number of widgets in
stock. Because all of the classes used to implement the substitution group inherit from the same base class, you can implement
checkWidgets() without using any JAXB specific APIs.
All of the classes generated to support the members of the substitution group for widget
extend the WidgetType class. Because of this fact, you can use instanceof to
determine what type of widget was passed in and simply cast the widgetPart object into the more
restrictive type if appropriate. Once you have the proper type of object, you can check the inventory of the right kind of
widget.
Example 14.15 shows a possible implementation.
Example 14.15. Service Implementation of checkWidgets()
public int checkWidgets(WidgetType widgetPart)
{
if (widgetPart instanceof WidgetType)
{
return checkWidgetInventory(widgetType);
}
else if (widgetPart instanceof WoodWidgetType)
{
WoodWidgetType widget = (WoodWidgetType)widgetPart;
return checkWoodWidgetInventory(widget);
}
else if (widgetPart instanceof PlasticWidgetType)
{
PlasticWidgetType widget = (PlasticWidgetType)widgetPart;
return checkPlasticWidgetInventory(widget);
}
}placeWidgetOrder uses two complex types containing the substitution group. This
operation demonstrates to use such a structure in a Java implementation. Both the consumer and the service must get and set
members of a substitution group.
To invoke placeWidgetOrder() the consumer must construct a widget order containing
one element of the widget substitution group. When adding the widget to the order, the consumer should use the object factory
methods generated for each element of the substitution group. This ensures that the runtime and the service can correctly process
the order. For example, if an order is being placed for a plastic widget,
the ObjectFactory.createPlasticWidget() method is used to create the element before adding it
to the order.
Example 14.16 shows consumer code for setting the
widget property of the WidgetOrderInfo object.
Example 14.16. Setting a Substitution Group Member
ObjectFactory of = new ObjectFactory();
WidgetOrderInfo order = new of.createWidgetOrderInfo();
...
System.out.println();
System.out.println("What color widgets do you want to order?");
String color = reader.readLine();
System.out.println();
System.out.println("What shape widgets do you want to order?");
String shape = reader.readLine();
System.out.println();
System.out.println("What type of widgets do you want to order?");
System.out.println("1 - Normal");
System.out.println("2 - Wood");
System.out.println("3 - Plastic");
System.out.println("Selection [1-3]");
String selection = reader.readLine();
String trimmed = selection.trim();
char widgetType = trimmed.charAt(0);
switch (widgetType)
{
case '1':
{
WidgetType widget = of.createWidgetType();
widget.setColor(color);
widget.setShape(shape);
JAXB<WidgetType> widgetElement = of.createWidget(widget);
order.setWidget(widgetElement);
break;
}
case '2':
{
WoodWidgetType woodWidget = of.createWoodWidgetType();
woodWidget.setColor(color);
woodWidget.setShape(shape);
System.out.println();
System.out.println("What type of wood are your widgets?");
String wood = reader.readLine();
woodWidget.setWoodType(wood);
JAXB<WoodWidgetType> widgetElement = of.createWoodWidget(woodWidget);
order.setWoodWidget(widgetElement);
break;
}
case '3':
{
PlasticWidgetType plasticWidget = of.createPlasticWidgetType();
plasticWidget.setColor(color);
plasticWidget.setShape(shape);
System.out.println();
System.out.println("What type of mold to use for your
widgets?");
String mold = reader.readLine();
plasticWidget.setMoldProcess(mold);
JAXB<WidgetType> widgetElement = of.createPlasticWidget(plasticWidget);
order.setPlasticWidget(widgetElement);
break;
}
default :
System.out.println("Invaid Widget Selection!!");
}The placeWidgetOrder() method receives an order in the form of a
WidgetOrderInfo object, processes the order, and returns a bill to the consumer in the form of a
WidgetOrderBillInfo object. The orders can be for a plain widget, a plastic widget, or a wooden
widget. The type of widget ordered is determined by what type of object is stored in
widgetOrderForm object’s widget property. The
widget property is a substitution group and can contain a widget element,
a woodWidget element, or a plasticWidget element.
The implementation must determine which of the possible elements is stored in the order. This can be accomplished using
the JAXBElement<? extends T> object's getName() method
to determine the element's QName. The QName can then be used to determine which element in the substitution group is in the
order. Once the element included in the bill is known, you can extract its value into the proper type of object.
Example 14.17 shows a possible implementation.
Example 14.17. Implementation of placeWidgetOrder()
public com.widgetvendor.types.widgettypes.WidgetOrderBillInfo placeWidgetOrder(WidgetOrderInfo widgetOrderForm)
{
ObjectFactory of = new ObjectFactory();
WidgetOrderBillInfo bill = new WidgetOrderBillInfo()
// Copy the shipping address and the number of widgets
// ordered from widgetOrderForm to bill
...
int numOrdered = widgetOrderForm.getAmount();
String elementName = widgetOrderForm.getWidget().getName().getLocalPart();
if (elementName.equals("woodWidget")
{
WoodWidgetType widget=order.getWidget().getValue();
buildWoodWidget(widget, numOrdered);
// Add the widget info to bill
JAXBElement<WoodWidgetType> widgetElement = of.createWoodWidget(widget);
bill.setWidget(widgetElement);
float amtDue = numOrdered * 0.75;
bill.setAmountDue(amtDue);
}
else if (elementName.equals("plasticWidget")
{
PlasticWidgetType widget=order.getWidget().getValue();
buildPlasticWidget(widget, numOrdered);
// Add the widget info to bill
JAXBElement<PlasticWidgetType> widgetElement = of.createPlasticWidget(widget);
bill.setWidget(widgetElement);
float amtDue = numOrdered * 0.90;
bill.setAmountDue(amtDue);
}
else
{
WidgetType widget=order.getWidget().getValue();
buildWidget(widget, numOrdered);
// Add the widget info to bill
JAXBElement<WidgetType> widgetElement = of.createWidget(widget);
bill.setWidget(widgetElement);
float amtDue = numOrdered * 0.30;
bill.setAmountDue(amtDue);
}
return(bill);
}The code in Example 14.17 does the following:
Instantiates an object factory to create elements. | |
Instantiates a | |
Gets the number of widgets ordered. | |
Gets the local name of the element stored in the order. | |
Checks to see if the element is a | |
Extracts the value of the element from the order to the proper type of object. | |
Creates a | |
Sets the bill object's widget property. | |
Sets the bill object's amountDue property. |
The JAXB specification defines a number of XML elements that customize how Java types are mapped to XML Schema constructs. These elements can be specified in-line with XML Schema constructs. If you cannot, or do not want to, modify the XML Schema definitions, you can specify the customizations in external binding document.
The elements used to customize the JAXB data bindings are defined in the namespace
http://java.sun.com/xml/ns/jaxb. You must add a namespace declaration similar to the one
shown in Example 15.1. This is added to the root element of all XML documents
defining JAXB customizations.
When using the JAXB customizations, you must indicate the JAXB version being used. This is done by adding a
jaxb:version attribute to the root element of the external binding declaration. If you are using in-line
customization, you must include the jaxb:version attribute in the
schema element containing the customizations. The value of the attribute is always
2.0.
Example 15.2 shows an example of the jaxb:version attribute used in a schema element.
The most direct way to customize how the code generators map XML Schema constructs to Java constructs is to add the
customization elements directly to the XML Schema definitions. The JAXB customization elements are placed inside the
xsd:appinfo element of the XML schema construct that is being modified.
Example 15.3 shows an example of a schema containing an in-line JAXB customization.
Example 15.3. Customized XML Schema
<schema targetNamespace="http://widget.com/types/widgetTypes" xmlns="http://www.w3.org/2001/XMLSchema" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" jaxb:version="2.0"> <complexType name="size"> <annotation> <appinfo> <jaxb:class name="widgetSize" /> </appinfo> </annotation> <sequence> <element name="longSize" type="xsd:string" /> <element name="numberSize" type="xsd:int" /> </sequence> </complexType> <schema>
When you cannot, or do not want to, make changes to the XML Schema document that defines your type, you can
specify the customizations using an external binding declaration. An external binding declaration consists of a number of nested
jaxb:bindings elements. Example 15.4 shows the
syntax of an external binding declaration.
Example 15.4. JAXB External Binding Declaration Syntax
<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xsd="http://www.w3.org/2001/XMLSchema" jaxb:version="2.0"> <jaxb:bindings [schemaLocation="schemaUri" | wsdlLocation="wsdlUri"> <jaxb:bindings node="nodeXPath"> binding declaration </jaxb:bindings> ... </jaxb:bindings> <jaxb:bindings>
The schemaLocation attribute and the wsdlLocation attribute
are used to identify the schema document to which the modifications are applied. Use the
schemaLocation attribute if you are generating code from a schema document. Use the
wsdlLocation attribute if you are generating code from a WSDL document.
The node attribute is used to identify the specific XML schema construct that is to be modified. It is an XPath statement that resolves to an XML Schema element.
Given the schema document widgetSchema.xsd, shown in Example 15.5, the external binding declaration shown in Example 15.6 modifies the generation of the complex type size.
Example 15.5. XML Schema File
<schema targetNamespace="http://widget.com/types/widgetTypes" xmlns="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" version="1.0"> <complexType name="size"> <sequence> <element name="longSize" type="xsd:string" /> <element name="numberSize" type="xsd:int" /> </sequence> </complexType> <schema>
Example 15.6. External Binding Declaration
<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xsd="http://www.w3.org/2001/XMLSchema" jaxb:version="2.0"> <jaxb:bindings schemaLocation="wsdlSchema.xsd"> <jaxb:bindings node="xsd:complexType[@name='size']"> <jaxb:class name="widgetSize" /> </jaxb:bindings> </jaxb:bindings> <jaxb:bindings>
To instruct the code generators to use the external binging declaration use the wsdl2java tool's
-b option, as shown below:binding-file
wsdl2java -b widgetBinding.xml widget.wsdlBy default, XML Schema types are mapped to Java primitive types. While this is the most logical mapping between XML Schema and Java, it does not always meet the requirements of the application developer. You might want to map an XML Schema primitive type to a Java class that can hold extra information, or you might want to map an XML primitive type to a class that allows for simple type substitution.
The JAXB javaType customization element allows you to customize the mapping between an
XML Schema primitive type and a Java primitive type. It can be used to customize the mappings at both the global level and the
individual instance level. You can use the javaType element as part of a simple type definition or
as part of a complex type definition.
When using the javaType customization element you must specify methods for converting the
XML representation of the primitive type to and from the target Java class. Some mappings have default conversion methods. For
instances where there are no default mappings, Fuse Services Framework provides JAXB methods to ease the development of the required
methods.
The javaType customization element takes four attributes, as described in
Table 15.1.
Table 15.1. Attributes for Customizing the Generation of a Java Class for an XML Schema Type
| Attribute | Required | Description |
|---|---|---|
name | Yes | Specifies the name of the Java class to which the XML Schema primitive type is mapped. It must be either a valid Java class name or the name of a Java primitive type. You must ensure that this class exists and is accessible to your application. The code generator does not check for this class. |
xmlType | No | Specifies the XML Schema primitive type that is being customized. This attribute is only used when the javaType element is used as a child of the globalBindings element. |
parseMethod | No | Specifies the method responsible for parsing the string-based XML representation of the data into an instance of the Java class. For more information see Specifying the converters. |
printMethod | No | Specifies the method responsible for converting a Java object to the string-based XML representation of the data. For more information see Specifying the converters. |
The javaType customization element can be used in three ways:
To modify all instances of an XML Schema primitive type — The javaType element
modifies all instances of an XML Schema type in the schema document when it is used as a child of the
globalBindings customization element. When it is used in this manner, you must specify a value
for the xmlType attribute that identifies the XML Schema primitive type being modified.
Example 15.7 shows an in-line global customization that instructs
the code generators to use java.lang.Integer for all instances of xsd:short in the
schema.
Example 15.7. Global Primitive Type Customization
<schema targetNamespace="http://widget.com/types/widgetTypes" xmlns="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" jaxb:version="2.0"> <annotation> <appinfo> <jaxb:globalBindings ...> <jaxb:javaType name="java.lang.Integer" xmlType="xsd:short" /> </globalBindings </appinfo> </annotation> ... </schema>
To modify a simple type definition — The javaType element modifies the class
generated for all instances of an XML simple type when it is applied to a named simple type definition. When using the
javaType element to modify a simple type definition, do not use the
xmlType attribute.
Example 15.8 shows an external binding file that modifies the generation of a simple type named zipCode.
Example 15.8. Binding File for Customizing a Simple Type
<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xsd="http://www.w3.org/2001/XMLSchema" jaxb:version="2.0"> <jaxb:bindings wsdlLocation="widgets.wsdl"> <jaxb:bindings node="xsd:simpleType[@name='zipCode']"> <jaxb:javaType name="com.widgetVendor.widgetTypes.zipCodeType" parseMethod="com.widgetVendor.widgetTypes.support.parseZipCode" printMethod="com.widgetVendor.widgetTypes.support.printZipCode" /> </jaxb:bindings> </jaxb:bindings> <jaxb:bindings>
To modify an element or attribute of a complex type definition — The javaType can
be applied to individual parts of a complex type definition by including it as part of a JAXB property customization. The
javaType element is placed as a child to the property's baseType
element. When using the javaType element to modify a specific part of a complex type definition,
do not use the xmlType attribute.
Example 15.9 shows a binding file that modifies an element of a complex type.
Example 15.9. Binding File for Customizing an Element in a Complex Type
<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xsd="http://www.w3.org/2001/XMLSchema" jaxb:version="2.0"> <jaxb:bindings schemaLocation="enumMap.xsd"> <jaxb:bindings node="xsd:ComplexType[@name='widgetOrderInfo']"> <jaxb:bindings node="xsd:element[@name='cost']"> <jaxb:property> <jaxb:baseType> <jaxb:javaType name="com.widgetVendor.widgetTypes.costType" parseMethod="parseCost" printMethod="printCost" > </jaxb:baseType> </jaxb:property> </jaxb:bindings> </jaxb:bindings> </jaxb:bindings> <jaxb:bindings>
For more information on using the baseType element see
Specifying the Base Type of an Element or an Attribute.
The Fuse Services Framework cannot convert XML Schema primitive types into random Java classes. When you use the
javaType element to customize the mapping of an XML Schema primitive type, the code generator
creates an adapter class that is used to marshal and unmarshal the customized XML Schema primitive type. A sample adapter
class is shown in Example 15.10.
Example 15.10. JAXB Adapter Class
public class Adapter1 extends XmlAdapter<String,javaType> { publicjavaTypeunmarshal(String value) { return(parseMethod(value)); } public String marshal(javaTypevalue) { return(printMethod(value)); } }
parseMethod and printMethod are replaced by the value of
the corresponding parseMethod attribute and printMethod attribute.
The values must identify valid Java methods. You can specify the method's name in one of two ways:
A fully qualified Java method name in the form of
packagename.ClassName.methodName
A simple method name in the form of methodName
When you only provide a simple method name, the code generator assumes that the method exists in the class specified by the javaType element's name attribute.
![]() | Important |
|---|---|
The code generators do not generate parse or print methods. You are responsible for supplying them. For information on developing parse and print methods see Implementing converters. |
If a value for the parseMethod attribute is not provided, the code generator assumes that the
Java class specified by the name attribute has a constructor whose first parameter is a Java
String object. The generated adapter's unmarshal() method uses
the assumed constructor to populate the Java object with the XML data.
If a value for the printMethod attribute is not provided, the code generator assumes that the
Java class specified by the name attribute has a toString()
method. The generated adapter's marshal() method uses the assumed
toString() method to convert the Java object to XML data.
If the javaType element's name attribute specifies a Java primitive type, or one of the Java primitive's wrapper types, the code generators use the default converters. For more information on default converters see Default primitive type converters.
As mentioned in Specifying the converters, using the
javaType customization element triggers the generation of one adapter class for each customization
of an XML Schema primitive type. The adapters are named in sequence using the pattern
Adapter. If you specify two primitive type customizations, the code
generators create two adapter classes: NAdapter1 and Adapter2.
The code generated for an XML schema construct depends on whether the effected XML Schema construct is a globally defined element or is defined as part of a complex type.
When the XML Schema construct is a globally defined element, the object factory method generated for the type is modified from the default method as follows:
The method is decorated with an @XmlJavaTypeAdapter annotation.
The annotation instructs the runtime which adapter class to use when processing instances of this element. The adapter class is specified as a class object.
The default type is replaced by the class specified by the javaType element's
name attribute.
Example 15.11 shows the object factory method for an element affected by the customization shown in Example 15.7.
Example 15.11. Customized Object Factory Method for a Global Element
@XmlElementDecl(namespace = "http://widgetVendor.com/types/widgetTypes", name = "shorty") @XmlJavaTypeAdapter(org.w3._2001.xmlschema.Adapter1 .class) public JAXBElement<Integer> createShorty(Integer value) { return new JAXBElement<Integer>(_Shorty_QNAME, Integer.class, null, value); }
When the XML Schema construct is defined as part of a complex type, the generated Java property is modified as follows:
The property is decorated with an @XmlJavaTypeAdapter annotation.
The annotation instructs the runtime which adapter class to use when processing instances of this element. The adapter class is specified as a class object.
The property's @XmlElement includes a type
property.
The value of the type property is the class object representing the generated object's default
base type. In the case of XML Schema primitive types, the class is String.
The property is decorated with an @XmlSchemaType annotation.
The annotation identifies the XML Schema primitive type of the construct.
The default type is replaced by the class specified by the javaType element's
name attribute.
Example 15.12 shows the object factory method for an element affected by the customization shown in Example 15.7.
Example 15.12. Customized Complex Type
public class NumInventory {
@XmlElement(required = true, type = String.class)
@XmlJavaTypeAdapter(Adapter1 .class)
@XmlSchemaType(name = "short")
protected Integer numLeft;
@XmlElement(required = true)
protected String size;
public Integer getNumLeft() {
return numLeft;
}
public void setNumLeft(Integer value) {
this.numLeft = value;
}
public String getSize() {
return size;
}
public void setSize(String value) {
this.size = value;
}
}The Fuse Services Framework runtime has does not know how to convert XML primitive types to and from the Java class specified by the
javaType element, except that it should call the methods specified by the
parseMethod attribute and the printMethod attribute. You are
responsible for providing implementations of the methods the runtime calls. The implemented methods must be capable of working
with the lexical structures of the XML primitive type.
To simplify the implementation of the data conversion methods, Fuse Services Framework provides the
javax.xml.bind.DatatypeConverter class. This class provides methods for parsing and printing all of the
XML Schema primitive types. The parse methods take string representations of the XML data and they return an instance of the
default type defined in Table 11.1. The print methods take an instance of the default type
and they return a string representation of the XML data.
The Java documentation for the DatatypeConverter class can be found at
http://java.sun.com/webservices/docs/1.6/api/javax/xml/bind/DatatypeConverter.html.
When specifying a Java primitive type, or one of the Java primitive type Wrapper classes, in the
javaType element's name attribute, it is not necessary to specify
values for the parseMethod attribute or the printMethod attribute.
The Fuse Services Framework runtime substitutes default converters if no values are provided.
The default data converters use the JAXB DatatypeConverter class to parse the XML data. The
default converters will also provide any type casting necessary to make the conversion work.
By default, named simple types do not result in generated types unless they are enumerations. Elements defined using a simple type are mapped to properties of a Java primitive type.
There are instances when you need to have simple types generated into Java classes, such as is when you want to use type substitution.
To instruct the code generators to generate classes for all globally defined simple types, set the
globalBindings customization element's mapSimpleTypeDef to
true.
To instruct the code generators to create Java classes for named simple types add the
globalBinding element's mapSimpleTypeDef attribute and set its value
to true.
Example 15.13 shows an in-line customization that forces the code generator to generate Java classes for named simple types.
Example 15.13. in-Line Customization to Force Generation of Java Classes for SimpleTypes
<schema targetNamespace="http://widget.com/types/widgetTypes" xmlns="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" jaxb:version="2.0"> <annotation> <appinfo> <jaxb:globalBindings mapSimpleTypeDef="true" /> </appinfo> </annotation> ... </schema>
Example 15.14 shows an external binding file that customizes the generation of simple types.
Example 15.14. Binding File to Force Generation of Constants
<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xsd="http://www.w3.org/2001/XMLSchema" jaxb:version="2.0"> <jaxb:bindings schemaLocation="types.xsd"> <jaxb:globalBindings mapSimpleTypeDef="true" /> <jaxb:bindings> <jaxb:bindings>
![]() | Important |
|---|---|
This customization only affects named simple types that are defined in the global scope. |
The class generated for a simple type has one property called value. The value property is of the Java type defined by the mappings in Primitive Types. The generated class has a getter and a setter for the value property.
Example 15.16 shows the Java class generated for the simple type defined in Example 15.15.
Example 15.15. Simple Type for Customized Mapping
<simpleType name="simpleton"> <restriction base="xsd:string"> <maxLength value="10"/> </restriction> </simpleType>
Example 15.16. Customized Mapping of a Simple Type
@XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "simpleton", propOrder = {"value"}) public class Simpleton { @XmlValue protected String value; public String getValue() { return value; } public void setValue(String value) { this.value = value; } }
If you want enumerated types that are based on a schema type other than xsd:string, you must instruct the code generator to map it. You can also control the name of the generated enumeration constants.
The customization is done using the jaxb:typesafeEnumClass element along with one or more
jaxb:typesafeEnumMember elements.
There might also be instances where the default settings for the code generator cannot create valid Java identifiers for all of
the members of an enumeration. You can customize how the code generators handle this by using an attribute of the
globalBindings customization.
If the code generator encounters a naming collision when generating the members of an enumeration or if it cannot create a valid Java identifier for a member of the enumeration, the code generator, by default, generates a warning and does not generate a Java enum type for the enumeration.
You can alter this behavior by adding the globalBinding element's
typesafeEnumMemberName attribute. The
typesafeEnumMemberName attribute's values are described in
Table 15.2.
Table 15.2. Values for Customizing Enumeration Member Name Generation
| Value | Description |
|---|---|
skipGeneration(default) | Specifies that the Java enum type is not generated and generates a warning. |
generateName | Specifies that member names will be generated following the pattern
VALUE_. N starts off at one, and is
incremented for each member of the enumeration. |
generateError | Specifies that the code generator generates an error when it cannot map an enumeration to a Java enum type. |
Example 15.17 shows an in-line customization that forces the code generator to generate type safe member names.
Example 15.17. Customization to Force Type Safe Member Names
<schema targetNamespace="http://widget.com/types/widgetTypes" xmlns="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" jaxb:version="2.0"> <annotation> <appinfo> <jaxb:globalBindings typesafeEnumMemberName="generateName" /> </appinfo> </annotation> ... </schema>
The jaxb:typesafeEnumClass element specifies that an XML Schema enumeration should be mapped to a Java enum type. It has two attributes that are described in Table 15.3. When the jaxb:typesafeEnumClass element is specified in-line, it must be placed inside the xsd:annotation element of the simple type it is modifying.
Table 15.3. Attributes for Customizing a Generated Enumeration Class
| Attribute | Description |
|---|---|
name | Specifies the name of the generated Java enum type. This value must be a valid Java identifier. |
map | Specifies if the enumeration should be mapped to a Java enum type. The default value is true. |
The jaxb:typesafeEnumMember element specifies the mapping between an XML Schema
enumeration facet and a Java enum type constant. You must use one
jaxb:typesafeEnumMember element for each enumeration facet
in the enumeration being customized.
When using in-line customization, this element can be used in one of two ways:
It can be placed inside the xsd:annotation element of the
enumeration facet it is modifying.
They can all be placed as children of the jaxb:typesafeEnumClass element used to
customize the enumeration.
The jaxb:typesafeEnumMember element has a name attribute that is required. The name attribute specifies the name of the generated Java enum type constant. It's value must be a valid Java identifier.
The jaxb:typesafeEnumMember element also has a value
attribute. The value is used to associate the enumeration facet with
the proper jaxb:typesafeEnumMember element. The value of the
value attribute must match one of the values of an enumeration
facets' value attribute. This attribute is required when you use an external binding specification for
customizing the type generation, or when you group the jaxb:typesafeEnumMember elements as
children of the jaxb:typesafeEnumClass element.
Example 15.18 shows an enumerated type that uses in-line customization and has the enumeration's members customized separately.
Example 15.18. In-line Customization of an Enumerated Type
<schema targetNamespace="http://widget.com/types/widgetTypes" xmlns="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" jaxb:version="2.0"> <simpleType name="widgetInteger"> <annotation> <appinfo> <jaxb:typesafeEnumClass /> </appinfo> </annotation> <restriction base="xsd:int"> <enumeration value="1"> <annotation> <appinfo> <jaxb:typesafeEnumMember name="one" /> </appinfo> </annotation> </enumeration> <enumeration value="2"> <annotation> <appinfo> <jaxb:typesafeEnumMember name="two" /> </appinfo> </annotation> </enumeration> <enumeration value="3"> <annotation> <appinfo> <jaxb:typesafeEnumMember name="three" /> </appinfo> </annotation> </enumeration> <enumeration value="4"> <annotation> <appinfo> <jaxb:typesafeEnumMember name="four" /> </appinfo> </annotation> </enumeration> </restriction> </simpleType> <schema>
Example 15.19 shows an enumerated type that uses in-line customization and combines the member's customization in the class customization.
Example 15.19. In-line Customization of an Enumerated Type Using a Combined Mapping
<schema targetNamespace="http://widget.com/types/widgetTypes" xmlns="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" jaxb:version="2.0"> <simpleType name="widgetInteger"> <annotation> <appinfo> <jaxb:typesafeEnumClass> <jaxb:typesafeEnumMember value="1" name="one" /> <jaxb:typesafeEnumMember value="2" name="two" /> <jaxb:typesafeEnumMember value="3" name="three" /> <jaxb:typesafeEnumMember value="4" name="four" /> </jaxb:typesafeEnumClass> </appinfo> </annotation> <restriction base="xsd:int"> <enumeration value="1" /> <enumeration value="2" /> <enumeration value="3" /> <enumeration value="4" > </restriction> </simpleType> <schema>
Example 15.20 shows an external binding file that customizes an enumerated type.
Example 15.20. Binding File for Customizing an Enumeration
<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xsd="http://www.w3.org/2001/XMLSchema" jaxb:version="2.0"> <jaxb:bindings schemaLocation="enumMap.xsd"> <jaxb:bindings node="xsd:simpleType[@name='widgetInteger']"> <jaxb:typesafeEnumClass> <jaxb:typesafeEnumMember value="1" name="one" /> <jaxb:typesafeEnumMember value="2" name="two" /> <jaxb:typesafeEnumMember value="3" name="three" /> <jaxb:typesafeEnumMember value="4" name="four" /> </jaxb:typesafeEnumClass> </jaxb:bindings> </jaxb:bindings> <jaxb:bindings>
By default, the code generators map attributes defined as having a fixed value to normal properties. When using schema validation, Fuse Services Framework can enforce the schema definition. However, using schema validation increases message processing time.
Another way to map attributes that have fixed values to Java is to map them to Java constants. You can instruct the code generator to map fixed value attributes to Java constants using the globalBindings customization element. You can also customize the mapping of fixed value attributes to Java constants at a more localized level using the property element.
You can alter this behavior by adding the globalBinding element's fixedAttributeAsConstantProperty attribute. Setting this attribute to true instructs the code generator to map any attribute defined using fixed attribute to a Java constant.
Example 15.21 shows an in-line customization that forces the code generator to generate constants for attributes with fixed values.
Example 15.21. in-Line Customization to Force Generation of Constants
<schema targetNamespace="http://widget.com/types/widgetTypes" xmlns="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" jaxb:version="2.0"> <annotation> <appinfo> <jaxb:globalBindings fixedAttributeAsConstantProperty="true" /> </appinfo> </annotation> ... </schema>
Example 15.22 shows an external binding file that customizes the generation of fixed attributes.
Example 15.22. Binding File to Force Generation of Constants
<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xsd="http://www.w3.org/2001/XMLSchema" jaxb:version="2.0"> <jaxb:bindings schemaLocation="types.xsd"> <jaxb:globalBindings fixedAttributeAsConstantProperty="true" /> <jaxb:bindings> <jaxb:bindings>
You can customize attribute mapping on a per-attribute basis using the property element's fixedAttributeAsConstantProperty attribute. Setting this attribute to true instructs the code generator to map any attribute defined using fixed attribute to a Java constant.
Example 15.23 shows an in-line customization that forces the code generator to generate constants for a single attribute with a fixed value.
Example 15.23. In-Line Customization to Force Generation of Constants
<schema targetNamespace="http://widget.com/types/widgetTypes" xmlns="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" jaxb:version="2.0"> <complexType name="widgetAttr"> <sequence> ... </sequence> <attribute name="fixer" type="xsd:int" fixed="7"> <annotation> <appinfo> <jaxb:property fixedAttributeAsConstantProperty="true" /> </appinfo> </annotation> </attribute> </complexType> ... </schema>
Example 15.24 shows an external binding file that customizes the generation of a fixed attribute.
Example 15.24. Binding File to Force Generation of Constants
<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xsd="http://www.w3.org/2001/XMLSchema" jaxb:version="2.0"> <jaxb:bindings schemaLocation="types.xsd"> <jaxb:bindings node="xsd:complexType[@name='widgetAttr']"> <jaxb:bindings node="xsd:attribute[@name='fixer']"> <jaxb:property fixedAttributeAsConstantProperty="true" /> </jaxb:bindings> </jaxb:bindings> </jaxb:bindings> <jaxb:bindings>
In the default mapping, all attributes are mapped to standard Java properties with getter and setter methods. When this
customization is applied to an attribute defined using the fixed attribute, the attribute is mapped to a
Java constant, as shown in Example 15.25.
Example 15.25. Mapping of a Fixed Value Attribute to a Java Constant
@XmlAttribute public final statictypeNAME=value;
type is determined by mapping the base type of the attribute to a Java type using the
mappings described in Primitive Types.
NAME is determined by converting the value of the
attribute element's name attribute to all capital letters.
value is determined by the value of the attribute element's
fixed attribute.
For example, the attribute defined in Example 15.23 is mapped as shown in Example 15.26.
Example 15.26. Fixed Value Attribute Mapped to a Java Constant
@XmlRootElement(name = "widgetAttr") public class WidgetAttr { ... @XmlAttribute public final static int FIXER = 7; ... }
Occasionally you need to customize the class of the object generated for an element, or for an attribute defined as part of an XML Schema complex type. For example, you might want to use a more generalized class of object to allow for simple type substitution.
One way to do this is to use the JAXB base type customization. It allows a developer, on a case by case basis, to specify the class of object generated to represent an element or an attribute. The base type customization allows you to specify an alternate mapping between the XML Schema construct and the generated Java object. This alternate mapping can be a simple specialization or a generalization of the default base class. It can also be a mapping of an XML Schema primitive type to a Java class.
To apply the JAXB base type property to an XML Schema construct use the JAXB
baseType customization element. The baseType customization
element is a child of the JAXB property element, so it must be properly nested.
Depending on how you want to customize the mapping of the XML Schema construct to Java object, you add either the
baseType customization element's name attribute, or a
javaType child element. The name attribute is used to map the
default class of the generated object to another class within the same class hierarchy. The javaType
element is used when you want to map XML Schema primitive types to a Java class.
![]() | Important |
|---|---|
You cannot use both the |
The baseType customization element's name attribute is used
to redefine the class of the generated object to a class within the same Java class hierarchy. The attribute specifies the fully qualified
name of the Java class to which the XML Schema construct is mapped. The specified Java class
must be either a super-class or a sub-class of the Java class that the code generator
normally generates for the XML Schema construct. For XML Schema primitive types that map to Java primitive types, the wrapper
class is used as the default base class for the purpose of customization.
For example, an element defined as being of xsd:int uses java.lang.Integer as
its default base class. The value of the name attribute can specify any super-class of
Integer such as Number or Object.
![]() | Tip |
|---|---|
For simple type substitution, the most common customization is to map the primitive types to an |
Example 15.27 shows an in-line customization that maps one element in a complex type to a Java Object object.
Example 15.27. In-Line Customization of a Base Type
<complexType name="widgetOrderInfo"> <all> <element name="amount" type="xsd:int" /> <element name="shippingAdress" type="Address> <annotation> <appinfo> <jaxb:property> <jaxb:baseType name="java.lang.Object" /> </jaxb:property> </appinfo> </annotation> </element> <element name="type" type="xsd:string"/> </all> </complexType>
Example 15.28 shows an external binding file for the customization shown in Example 15.27.
Example 15.28. External Binding File to Customize a Base Type
<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xsd="http://www.w3.org/2001/XMLSchema" jaxb:version="2.0"> <jaxb:bindings schemaLocation="enumMap.xsd"> <jaxb:bindings node="xsd:ComplexType[@name='widgetOrderInfo']"> <jaxb:bindings node="xsd:element[@name='shippingAddress']"> <jaxb:property> <jaxb:baseType name="java.lang.Object" /> </jaxb:property> </jaxb:bindings> </jaxb:bindings> </jaxb:bindings> <jaxb:bindings>
The resulting Java object's @XmlElement annotation includes a type property. The
value of the type property is the class object representing the generated object's default base type. In
the case of XML Schema primitive types, the class is the wrapper class of the corresponding Java primitive type.
Example 15.29 shows the class generated based on the schema definition in Example 15.28.
Example 15.29. Java Class with a Modified Base Class
public class WidgetOrderInfo {
protected int amount;
@XmlElement(required = true)
protected String type;
@XmlElement(required = true, type = Address.class)
protected Object shippingAddress;
...
public Object getShippingAddress() {
return shippingAddress;
}
public void setShippingAddress(Object value) {
this.shippingAddress = value;
}
}The javaType element can be used to customize how elements and attributes defined using
XML Schema primitive types are mapped to Java objects. Using the javaType element provides a lot
more flexibility than simply using the baseType element's name
attribute. The javaType element allows you to map a primitive type to any class of object.
For a detailed description of using the javaType element, see
Specifying the Java Class of an XML Schema Primitive.
The JAXBContext object allows the Fuse Services Framework's runtime to transform data between XML elements and Java object. Application
developers need to instantiate a JAXBContext object they want to use JAXB objects in message handlers and when implementing consumers
that work with raw XML messages.
The JAXBContext object is a low-level object used by the runtime. It allows the runtime to convert between XML elements
and their corresponding Java representations. An application developer generally does not need to work with JAXBContext objects.
The marshaling and unmarshaling of XML data is typically handled by the transport and binding layers of a JAX-WS application.
However, there are instances when an application will need to manipulate the XML message content directly. In two of these instances:
You will need instantiate a JAXBContext object using one of the two available
JAXBContext.newInstance() methods.
JAXBContext objects are resource intensive to instantiate. It is recommended that an application create as few instances as possible. One way
to do this is to create a single JAXBContext object that can manage all of the JAXB objects used by your application and share it among as many
parts of your application as possible.
![]() | Tip |
|---|---|
|
The JAXBContext class provides a newInstance() method, shown in
Example 16.1, that takes a list of classes that implement JAXB objects.
Example 16.1. Getting a JAXB Context Using Classes
static JAXBContext newInstance(Class... classesToBeBound)
throws JAXBException;The returned JAXBObject object will be able to marshal and unmarshal data for the JAXB object implemented by the classes
passed into the method. It will also be able to work with any classes that are statically referenced from any of the classes passed into the method.
While it is possible to pass the name of every JAXB class used by your application to the newInstance() method it is
not efficient. A more efficient way to accomplish the same goal is to pass in the object factory, or object factories, generated for your application. The resulting
JAXBContext object will be able to manage any JAXB classes the specified object factories can instantiate.
The JAXBContext class provides a newInstance() method, shown in
Example 16.2, that takes a colon (:) seperated list of package names. The specified packages
should contain JAXB objects derived from XML Schema.
Example 16.2. Getting a JAXB Context Using Classes
static JAXBContext newInstance(String contextPath)
throws JAXBException;The returned JAXBContext object will be able to marshal and unmarshal data for all of the JAXB objects implemented by the classes
in the specified packages.
While the JAX-WS APIs make creating services and consumers easy, it also offers a number of advanced APIs. These APIs allow you to make asynchronous requests on a service, access message and transport properties, and develop services that process raw XML messages. They also allow you to develop custom message handlers.
Table of Contents
The SOAP over JMS protocol is defined by the World Wide Web Consortium(W3C) as a way of providing a more reliable transport layer to the customary SOAP/HTTP protocol used by most services. The Fuse Services Framework implementation is fully compliant with the specification and should be compatible with any framework that is also compliant.
This transport uses JNDI to find the JMS destinations. When an operation is invoked, the request is packaged as a SOAP message and sent in the body of a JMS message to the specified destination.
Publishing and consuming SOAP/JMS services differ from SOAP/HTTP services in the following ways:
SOAP/JMS service addressed are specified using a special JMS URI
you must use the Fuse Services Framework specific factory objects to use SOAP/JMS endpoints
JMS endpoints use a JMS URI as defined in the URI Scheme for JMS 1.0. Example 17.1 shows the syntax for a JMS URI.
Table 17.1 describes the available variants for the JMS URI.
Table 17.1. JMS URI variants
| Variant | Description |
|---|---|
| jndi | Specifies that the destination is a JNDI name for the target destination. When using this variant, you must provide the configuration for accessing the JNDI provider. |
| topic | Specifies that the destination is the name of the topic to be used as the
target destination. The string provided is passed into
Session.createTopic() to create a representation of the
destination. |
| queue | Specifies that the destination is the name of the queue to be used as the
target destination. The string provided is passed into
Session.createQueue() to create a representation of the
destination. |
Table 17.2 shows the URI options.
Table 17.2. JMS properties settable as URI options
| Property | Default | Description |
|---|---|---|
deliveryMode | PERSISTENT | Specifies whether to use JMS PERSISTENT or
NON_PERSISTENT message semantics. In the case of
PERSISTENT delivery mode, the JMS broker stores
messages in persistent storage before acknowledging them; whereas
NON_PERSISTENT messages are kept in memory
only. |
replyToName |
Explicitly specifies the reply destination to appear in the
The value of this property has an interpretation that depends on the variant specified in the JMS URI:
| |
priority | 4 | Specifies the JMS message priority, which ranges from 0 (lowest) to 9 (highest). |
timeToLive | 0 | Time (in milliseconds) after which the message will be discarded
by the JMS provider. 0 represents an
infinite lifetime. |
jndiConnectionFactoryName | Specifies the JNDI name of the JMS connection factory. | |
jndiInitialContextFactory | Specifies the fully qualified Java class name of the JNDI
provider (which must be of
javax.jms.InitialContextFactory type). Equivalent
to setting the java.naming.factory.initial Java system
property. | |
jndiURL | Specifies the URL that initializes the JNDI provider. Equivalent
to setting the java.naming.provider.url Java system
property. |
The JAX-WS standard publish() method cannot be used to publish
a SOAP/JMS service. Instead, you must use the Fuse Services Framework's
JaxWsServerFactoryBean class as shown in
Example 17.2.
Example 17.2. Publishing a SOAP/JMS service
String address = "jms:jndi:dynamicQueues/test.cxf.jmstransport.queue3" + "?jndiInitialContextFactory" + "=org.apache.activemq.jndi.ActiveMQInitialContextFactory" + "&jndiConnectionFactoryName=ConnectionFactory" + "&jndiURL=tcp://localhost:61500"; Hello implementor = new HelloImpl();
JaxWsServerFactoryBean svrFactory = new JaxWsServerFactoryBean(); svrFactory.setServiceClass(Hello.class);
svrFactory.setAddress(address);
svrFactory.setTransportId(JMSSpecConstants.SOAP_JMS_SPECIFICIATION_TRANSPORTID); svrFactory.setServiceBean(implementor); svrFactory.create();
The code in Example 17.2 does the following:
The standard JAX-WS APIs cannot be used to consume a SOAP/JMS service. Instead, you
must use the Fuse Services Framework's JaxWsProxyFactoryBean class as shown in
Example 17.3.
Example 17.3. Consuming a SOAP/JMS service
// Java
public void invoke() throws Exception {
String address = "jms:jndi:dynamicQueues/test.cxf.jmstransport.queue3"
+ "?jndiInitialContextFactory"
+ "=org.apache.activemq.jndi.ActiveMQInitialContextFactory"
+ "&jndiConnectionFactoryName=ConnectionFactory&jndiURL=tcp://localhost:61500";
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setAddress(address);
factory.setTransportId(JMSSpecConstants.SOAP_JMS_SPECIFICIATION_TRANSPORTID);
factory.setServiceClass(Hello.class);
Hello client = (Hello)factory.create();
String reply = client.sayHi(" HI");
System.out.println(reply);
}The code in Example 17.3 does the following:
JAX-WS provides an easy mechanism for accessing services asynchronously. The SEI can specify additional methods that can be used to access a service asynchronously. The Fuse Services Framework code generators generate the extra methods for you. You simply add the business logic.
In addition to the usual synchronous mode of invocation, Fuse Services Framework supports two forms of asynchronous invocation:
Polling approach — To invoke the remote operation using the polling approach, you call a method that has no
output parameters, but returns a javax.xml.ws.Response object. The
Response object (which inherits from the
javax.util.concurrency.Future interface) can be polled to check whether or not a response
message has arrived.
Callback approach — To invoke the remote operation using the callback approach, you call a method that takes a
reference to a callback object (of javax.xml.ws.AsyncHandler type) as one of its parameters.
When the response message arrives at the client, the runtime calls back on the AsyncHandler object,
and gives it the contents of the response message.
Example 18.1 shows the WSDL contract that is used for the asynchronous examples. The contract defines a single interface, GreeterAsync, which contains a single operation, greetMeSometime.
Example 18.1. WSDL Contract for Asynchronous Example
<?xml version="1.0" encoding="UTF-8"?><wsdl:definitions xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://apache.org/hello_world_async_soap_http" xmlns:x1="http://apache.org/hello_world_async_soap_http/types" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://apache.org/hello_world_async_soap_http" name="HelloWorld"> <wsdl:types> <schema targetNamespace="http://apache.org/hello_world_async_soap_http/types" xmlns="http://www.w3.org/2001/XMLSchema" xmlns:x1="http://apache.org/hello_world_async_soap_http/types" elementFormDefault="qualified"> <element name="greetMeSometime"> <complexType> <sequence> <element name="requestType" type="xsd:string"/> </sequence> </complexType> </element> <element name="greetMeSometimeResponse"> <complexType> <sequence> <element name="responseType" type="xsd:string"/> </sequence> </complexType> </element> </schema> </wsdl:types> <wsdl:message name="greetMeSometimeRequest"> <wsdl:part name="in" element="x1:greetMeSometime"/> </wsdl:message> <wsdl:message name="greetMeSometimeResponse"> <wsdl:part name="out" element="x1:greetMeSometimeResponse"/> </wsdl:message> <wsdl:portType name="GreeterAsync"> <wsdl:operation name="greetMeSometime"> <wsdl:input name="greetMeSometimeRequest" message="tns:greetMeSometimeRequest"/> <wsdl:output name="greetMeSometimeResponse" message="tns:greetMeSometimeResponse"/> </wsdl:operation> </wsdl:portType> <wsdl:binding name="GreeterAsync_SOAPBinding" type="tns:GreeterAsync"> ... </wsdl:binding> <wsdl:service name="SOAPService"> <wsdl:port name="SoapPort" binding="tns:GreeterAsync_SOAPBinding"> <soap:address location="http://localhost:9000/SoapContext/SoapPort"/> </wsdl:port> </wsdl:service> </wsdl:definitions>
The asynchronous style of invocation requires extra stub code for the dedicated asynchronous methods defined on the SEI. This special stub code is not generated by default. To switch on the asynchronous feature and generate the requisite stub code, you must use the mapping customization feature from the WSDL 2.0 specification.
Customization enables you to modify the way the Maven code generation plug-in generates stub code. In particular,
it enables you to modify the WSDL-to-Java mapping and to switch on certain features. Here, customization is used to switch on the
asynchronous invocation feature. Customizations are specified using a binding declaration, which you define using a
jaxws:bindings tag (where the jaxws prefix is tied to the
http://java.sun.com/xml/ns/jaxws namespace). There are two ways of specifying a binding
declaration:
When using an external binding declaration the jaxws:bindings element is defined in a
file separate from the WSDL contract. You specify the location of the binding declaration file to
code generator when you generate the stub code.
When using an embedded binding declaration you embed the jaxws:bindings element
directly in a WSDL contract, treating it as a WSDL extension. In this case, the settings in
jaxws:bindings apply only to the immediate parent element.
The template for a binding declaration file that switches on asynchronous invocations is shown in Example 18.2.
Example 18.2. Template for an Asynchronous Binding Declaration
<bindings xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" wsdlLocation="AffectedWSDL" xmlns="http://java.sun.com/xml/ns/jaxws"> <bindings node="AffectedNode"> <enableAsyncMapping>true</enableAsyncMapping> </bindings> </bindings>
Where AffectedWSDL specifies the URL of the WSDL contract that is affected by this binding
declaration. The AffectedNode is an XPath value that specifies which node (or nodes) from the
WSDL contract are affected by this binding declaration. You can set AffectedNode to
wsdl:definitions, if you want the entire WSDL contract to be affected. The
jaxws:enableAsyncMapping element is set to true to enable the
asynchronous invocation feature.
For example, if you want to generate asynchronous methods only for the
GreeterAsync interface, you can specify
<bindings node="wsdl:definitions/wsdl:portType[@name='GreeterAsync']"> in the preceding binding
declaration.
Assuming that the binding declaration is stored in a file, async_binding.xml,
you would set up your POM as shown in Example 18.3.
Example 18.3. Consumer Code Generation
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>${cxf.version}</version>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<configuration>
<sourceRoot>outputDir</sourceRoot>
<wsdlOptions>
<wsdlOption>
<wsdl>hello_world.wsdl</wsdl>
<extraargs>
<extraarg>-client</extraarg>
<extraarg>-b async_binding.xml</extraarg>
</extraargs>
</wsdlOption>
</wsdlOptions>
</configuration>
<goals>
<goal>wsdl2java</goal>
</goals>
</execution>
</executions>
</plugin>The -b option tells the code generator where to locate the external binding file.
For more information on the code generator see cxf-codegen-plugin.
You can also embed the binding customization directly into the WSDL document defining the service by placing the
jaxws:bindings element and its associated
jaxws:enableAsynchMapping child directly into the WSDL. You also must add a namespace
declaration for the jaxws prefix.
Example 18.4 shows a WSDL file with an embedded binding declaration that activates the asynchronous mapping for an operation.
Example 18.4. WSDL with Embedded Binding Declaration for Asynchronous Mapping
<wsdl:definitions xmlns="http://schemas.xmlsoap.org/wsdl/" ... xmlns:jaxws="http://java.sun.com/xml/ns/jaxws" ...> ... <wsdl:portType name="GreeterAsync"> <wsdl:operation name="greetMeSometime"> <jaxws:bindings> <jaxws:enableAsyncMapping>true</jaxws:enableAsyncMapping> </jaxws:bindings> <wsdl:input name="greetMeSometimeRequest" message="tns:greetMeSometimeRequest"/> <wsdl:output name="greetMeSometimeResponse" message="tns:greetMeSometimeResponse"/> </wsdl:operation> </wsdl:portType> ... </wsdl:definitions>
When embedding the binding declaration into the WSDL document you can control the scope affected by the declaration by
changing where you place the declaration. When the declaration is placed as a child of the
wsdl:definitions element the code generator creates asynchronous methods for all of the operations
defined in the WSDL document. If it is placed as a child of a wsdl:portType element the code
generator creates asynchronous methods for all of the operations defined in the interface. If it is placed as a child of a
wsdl:operation element the code generator creates asynchronous methods for only that
operation.
It is not necessary to pass any special options to the code generator when using embedded declarations. The code generator will recognize them and act accordingly.
After generating the stub code in this way, the GreeterAsync SEI (in the file
GreeterAsync.java) is defined as shown in
Example 18.5.
Example 18.5. Service Endpoint Interface with Methods for Asynchronous Invocations
package org.apache.hello_world_async_soap_http;
import org.apache.hello_world_async_soap_http.types.GreetMeSometimeResponse;
...
public interface GreeterAsync
{
public Future<?> greetMeSometimeAsync(
java.lang.String requestType,
AsyncHandler<GreetMeSometimeResponse> asyncHandler
);
public Response<GreetMeSometimeResponse> greetMeSometimeAsync(
java.lang.String requestType
);
public java.lang.String greetMeSometime(
java.lang.String requestType
);
}In addition to the usual synchronous method, greetMeSometime(), two asynchronous
methods are also generated for the greetMeSometime operation:
The polling approach is the more straightforward of the two approaches to developing an asynchronous application. The
client invokes the asynchronous method called
and is returned a
OperationNameAsync()Response<T> object that it polls for a response. What the client does while it is waiting for a
response is depends on the requirements of the application. There are two basic patterns for handling the polling:
Non-blocking polling — You periodically check to see if the result is ready
by calling the non-blocking Response<T>.isDone() method. If the result is ready, the client
processes it. If it not, the client continues doing other things.
Blocking polling — You call
Response<T>.get() right away, and block until the response arrives (optionally specifying
a timeout).
Example 18.6 illustrates using non-blocking polling to make an asynchronous invocation on the greetMeSometime operation defined in Example 18.1. The client invokes the asynchronous operation and periodically checks to see if the result is returned.
Example 18.6. Non-Blocking Polling Approach for an Asynchronous Operation Call
package demo.hw.client;
import java.io.File;
import java.util.concurrent.Future;
import javax.xml.namespace.QName;
import javax.xml.ws.Response;
import org.apache.hello_world_async_soap_http.*;
public final class Client {
private static final QName SERVICE_NAME
= new QName("http://apache.org/hello_world_async_soap_http",
"SOAPService");
private Client() {}
public static void main(String args[]) throws Exception {
// set up the proxy for the client
Response<GreetMeSometimeResponse> greetMeSomeTimeResp =
port.greetMeSometimeAsync(System.getProperty("user.name"));
while (!greetMeSomeTimeResp.isDone()) {
// client does some work
}
GreetMeSometimeResponse reply = greetMeSomeTimeResp.get();
// process the response
System.exit(0);
}
}The code in Example 18.6 does the following:
Invokes the The method call returns the
| ||||
Checks to see if a response has arrived by checking the If the response has not arrived, the client continues working before checking again. | ||||
When the response arrives, the client retrieves it from the |
When using the block polling pattern, the Response object's
isDone() is never called. Instead, the Response object's
get() method is called immediately after invoking the remote operation. The
get() blocks until the response is available.
![]() | Tip |
|---|---|
You can also pass a timeout limit to the |
Example 18.7 shows a client that uses blocking polling.
Example 18.7. Blocking Polling Approach for an Asynchronous Operation Call
package demo.hw.client;
import java.io.File;
import java.util.concurrent.Future;
import javax.xml.namespace.QName;
import javax.xml.ws.Response;
import org.apache.hello_world_async_soap_http.*;
public final class Client {
private static final QName SERVICE_NAME
= new QName("http://apache.org/hello_world_async_soap_http",
"SOAPService");
private Client() {}
public static void main(String args[]) throws Exception {
// set up the proxy for the client
Response<GreetMeSometimeResponse> greetMeSomeTimeResp =
port.greetMeSometimeAsync(System.getProperty("user.name"));
GreetMeSometimeResponse reply = greetMeSomeTimeResp.get();
// process the response
System.exit(0);
}
}An alternative approach to making an asynchronous operation invocation is to implement a callback class. You then call the asynchronous remote method that takes the callback object as a parameter. The runtime returns the response to the callback object.
To implement an application that uses callbacks, do the following:
Create a callback class that implements the AsyncHandler interface.
![]() | Note |
|---|---|
Your callback object can perform any amount of response processing required by your application. |
Make remote invocations using the that takes the callback object as a parameter and returns a operationNameAsync()Future<?> object.
If your client requires access to the response data, you can poll the returned
Future<?> object's isDone() method to see if the remote
endpoint has sent the response.
![]() | Tip |
|---|---|
If the callback object does all of the response processing, it is not necessary to check if the response has arrived. |
The callback class must implement the javax.xml.ws.AsyncHandler interface. The
interface defines a single method:
void handleResponse(Response<T> res);The Fuse Services Framework runtime calls the handleResponse() method to notify the client that the
response has arrived. Example 18.8 shows an outline of the
AsyncHandler interface that you must implement.
Example 18.8. The javax.xml.ws.AsyncHandler Interface
public interface javax.xml.ws.AsyncHandler
{
void handleResponse(Response<T> res)
}Example 18.9 shows a callback class for the greetMeSometime operation defined in Example 18.1.
Example 18.9. Callback Implementation Class
package demo.hw.client;
import javax.xml.ws.AsyncHandler;
import javax.xml.ws.Response;
import org.apache.hello_world_async_soap_http.types.*;
public class GreeterAsyncHandler implements AsyncHandler<GreetMeSometimeResponse>
{
private GreetMeSometimeResponse reply;
public void handleResponse(Response<GreetMeSometimeResponse>
response)
{
try
{
reply = response.get();
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
public String getResponse()
{
return reply.getResponseType();
}
}The callback implementation shown in Example 18.9 does the following:
Defines a member variable, | |
Implements This implementation simply extracts the response and assigns it to the member variable | |
Implements an added method called This method is a convenience method that extracts the data from |
Example 18.10 illustrates a client that uses the callback approach to make an asynchronous call to the GreetMeSometime operation defined in Example 18.1.
Example 18.10. Callback Approach for an Asynchronous Operation Call
package demo.hw.client;
import java.io.File;
import java.util.concurrent.Future;
import javax.xml.namespace.QName;
import javax.xml.ws.Response;
import org.apache.hello_world_async_soap_http.*;
public final class Client {
...
public static void main(String args[]) throws Exception
{
...
// Callback approach
GreeterAsyncHandler callback = new GreeterAsyncHandler();
Future<?> response =
port.greetMeSometimeAsync(System.getProperty("user.name"),
callback);
while (!response.isDone())
{
// Do some work
}
resp = callback.getResponse();
...
System.exit(0);
}
}The code in Example 18.10 does the following:
Instantiates a callback object. | ||||
Invokes the The method call returns the
| ||||
Uses the returned | ||||
Invokes the callback object's |
Consumers making asynchronous requests will not receive the same exceptions returned than when they make synchronous requests. Any
exceptions returned to the consumer asynchronously are wrapped in an ExecutionException exception.
The actual exception thrown by the service is stored in the ExecutionException exception's
cause field.
Exceptions generated by a remote service are thrown locally by the method that passes the response to the consumer's business logic.
When the consumer makes a synchronous request, the method making the remote invocation throws the exception. When the consumer makes
an asynchronous request, the Response<T> object's get() method
throws the exception. The consumer will not discover that an error was encountered in processing the request until it attempts to retrieve
the response message.
Unlike the methods generated by the JAX-WS framework, the Response<T>
object's get() method does not throw either user modeled exceptions nor the generic JAX-WS exceptions.
Instead, it throws a java.util.concurrent.ExecutionException exception.
The framework stores the exception returned from the remote service in the ExecutionException
exception's cause field. The details about the remote exception are extracted by getting the value of the
cause field and examining the stored exception. The stored exception can be any user defined exception or one
of the generic JAX-WS exceptions.
Example 18.11 shows an example of catching an exception using the polling approach.
Example 18.11. Catching an Exception using the Polling Approach
package demo.hw.client;
import java.io.File;
import java.util.concurrent.Future;
import javax.xml.namespace.QName;
import javax.xml.ws.Response;
import org.apache.hello_world_async_soap_http.*;
public final class Client
{
private static final QName SERVICE_NAME
= new QName("http://apache.org/hello_world_async_soap_http",
"SOAPService");
private Client() {}
public static void main(String args[]) throws Exception
{
...
// port is a previously established proxy object.
Response<GreetMeSometimeResponse> resp =
port.greetMeSometimeAsync(System.getProperty("user.name"));
while (!resp.isDone())
{
// client does some work
}
try
{
GreetMeSometimeResponse reply = greetMeSomeTimeResp.get();
// process the response
}
catch (ExecutionException ee)
{
Throwable cause = ee.getCause();
System.out.println("Exception "+cause.getClass().getName()+" thrown by the remote service.");
}
}
}The code in Example 18.11 does the following:
Wraps the call to the | |
Catches a | |
Extracts the |
If the consumer was using the callback approach the code used to catch the exception would be placed in the callback object where the service's response is extracted.
The high-level JAX-WS APIs shield the developer from using native XML messages by marshaling the data into JAXB objects.
However, there are cases when it is better to have direct access to the raw XML message data that is passing on the wire. The
JAX-WS APIs provide two interfaces that provide access to the raw XML: the Dispatch interface is
the client-side interface, and the Provider interface is the server-side interface.
The Dispatch interface is a low-level JAX-WS API that allows you work directly with raw
messages. It accepts and returns messages, or payloads, of a number of types including DOM objects, SOAP messages, and JAXB
objects. Because it is a low-level API, the Dispatch interface does not perform any of the
message preparation that the higher-level JAX-WS APIs perform. You must ensure that the messages, or payloads, that you pass to
the Dispatch object are properly constructed, and make sense for the remote operation being
invoked.
Dispatch objects have two usage modes:
Message mode
Message Payload mode (Payload mode)
The usage mode you specify for a Dispatch object determines the amount of detail
that is passed to the user level code.
In message mode, a Dispatch object works with complete
messages. A complete message includes any binding specific headers and wrappers. For example, a consumer interacting with a
service that requires SOAP messages must provide the Dispatch object's
invoke() method a fully specified SOAP message. The
invoke() method also returns a fully specified SOAP message. The consumer code is responsible
for completing and reading the SOAP message's headers and the SOAP message's envelope information.
![]() | Tip |
|---|---|
Message mode is not ideal when working with JAXB objects. |
To specify that a Dispatch object uses message mode provide the value
java.xml.ws.Service.Mode.MESSAGE when creating the Dispatch
object. For more information about creating a Dispatch object see
Creating a Dispatch object.
In payload mode, also called message payload mode, a
Dispatch object works with only the payload of a message. For example, a
Dispatch object working in payload mode works only with the body of a SOAP message. The
binding layer processes any binding level wrappers and headers. When a result is returned from the
invoke() method the binding level wrappers and headers are already striped away, and only the
body of the message is left.
![]() | Tip |
|---|---|
When working with a binding that does not use special wrappers, such as the Fuse Services Framework XML binding, payload mode and message mode provide the same results. |
To specify that a Dispatch object uses payload mode provide the value
java.xml.ws.Service.Mode.PAYLOAD when creating the Dispatch
object. For more information about creating a Dispatch object see
Creating a Dispatch object.
Because Dispatch objects are low-level objects, they are not optimized for using the
same JAXB generated types as the higher level consumer APIs. Dispatch objects work with the
following types of objects:
A Dispatch object accepts and returns objects that are derived from the
javax.xml.transform.Source interface. Source objects are
supported by any binding, and in either message mode or payload mode.
Source objects are low level objects that hold XML documents. Each
Source implementation provides methods that access the stored XML documents and then
manipulate its contents. The following objects implement the Source interface:
DOMSourceHolds XML messages as a Document Object Model(DOM) tree. The XML message is stored as a set of
Node objects that are accessed using the getNode()
method. Nodes can be either updated or added to the DOM tree using the setNode()
method.
SAXSourceHolds XML messages as a Simple API for XML (SAX) object. SAX objects contain an
InputSource object that holds the raw data and an XMLReader
object that parses the raw data.
StreamSourceHolds XML messages as a data stream. The data stream can be manipulated the same as any other data stream.
If you create your Dispatch object so that it uses generic
Source objects, Fuse Services Framework returns the messages as
SAXSource objects.
This behavior can be changed using the endpoint's source-preferred-format property. See Configuring Web Service Endpoints for information about configuring the Fuse Services Framework runtime.
Dispatch objects can use javax.xml.soap.SOAPMessage
objects when the following conditions are true:
The Dispatch object is using the SOAP binding
The Dispatch object is using message mode
A SOAPMessage object holds a SOAP message. They contain one
SOAPPart object and zero or more AttachmentPart objects. The
SOAPPart object contains the SOAP specific portions of the SOAP message including the SOAP
envelope, any SOAP headers, and the SOAP message body. The AttachmentPart objects contain
binary data that is passed as an attachment.
Dispatch objects can use objects that implement the
javax.activation.DataSource interface when the following conditions are true:
The Dispatch object is using the HTTP binding
The Dispatch object is using message mode
DataSource objects provide a mechanism for working with MIME typed data from a
variety of sources, including URLs, files, and byte arrays.
While Dispatch objects are intended to be low level APIs that allow you to work with
raw messages, they also allow you to work with JAXB objects. To work with JAXB objects a
Dispatch object must be passed a JAXBContext that can
marshal and unmarshal the JAXB objects in use. The JAXBContext is passed when the
Dispatch object is created.
You can pass any JAXB object understood by the JAXBContext object as the
parameter to the invoke() method. You can also cast the returned message
into any JAXB object understood by the JAXBContext object.
For information on creating a JAXBContext object see Using A JAXBContext Object.
To use a Dispatch object to invoke a remote service the following sequence should
be followed:
To create a Dispatch object do the following:
Create a Service object to represent the wsdl:service element
that defines the service on which the Dispatch object will make invocations. See
Creating a Service Object.
Create the Dispatch object using the Service object's
createDispatch() method, shown in Example 19.1.
Example 19.1. The createDispatch() Method
public Dispatch<T> createDispatch(QName portName,
java.lang.Class<T> type,
Service.Mode mode)
throws WebServiceException;![]() | Note |
|---|---|
If you are using JAXB objects the method signature for public Dispatch<T> createDispatch(QName portName, |
Table 19.1 describes the parameters for the
createDispatch() method.
Table 19.1. Parameters for createDispatch()
| Parameter | Description |
|---|---|
portName | Specifies the QName of the wsdl:port element that represents the service provider
where the Dispatch object will make invocations. |
type |
Specifies the data type of the objects used by the When working with JAXB objects, this parameter specifies the |
mode | Specifies the usage mode for the Dispatch object. See Usage Modes. |
Example 19.2 shows the code for creating a
Dispatch object that works with DOMSource objects in payload
mode.
Example 19.2. Creating a Dispatch Object
package com.fusesource.demo;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
public class Client
{
public static void main(String args[])
{
QName serviceName = new QName("http://org.apache.cxf", "stockQuoteReporter");
Service s = Service.create(serviceName);
QName portName = new QName("http://org.apache.cxf", "stockQuoteReporterPort");
Dispatch<DOMSource> dispatch = s.createDispatch(portName,
DOMSource.class,
Service.Mode.PAYLOAD);
...When working with Dispatch objects, requests must be built from scratch. The
developer is responsible for ensuring that the messages passed to a Dispatch object match a
request that the targeted service provider can process. This requires precise knowledge about the messages used by the service
provider and what, if any, header information it requires.
This information can be provided by a WSDL document or an XML Schema document that defines the messages. While service providers vary greatly there are a few guidelines to be followed:
The root element of the request is based in the value of the name attribute of the
wsdl:operation element corresponding to the operation being invoked.
![]() | Warning |
|---|---|
If the service being invoked uses doc/literal bare messages, the root element of the request is based on the value of
the |
The root element of the request is namespace qualified.
If the service being invoked uses rpc/literal messages, the top-level elements in the request will not be namespace qualified.
![]() | Important |
|---|---|
The children of top-level elements may be namespace qualified. To be certain you must check their schema definitions. |
If the service being invoked uses rpc/literal messages, none of the top-level elements can be null.
If the service being invoked uses doc/literal messages, the schema definition of the message determines if any of the elements are namespace qualified.
For more information about how services use XML messages see, the WS-I Basic Profile.
For consumers that make synchronous invocations that generate a response, use the
Dispatch object's invoke() method shown in
Example 19.3.
The type of both the response and the request passed to the invoke() method are
determined when the Dispatch object is created. For example if you create a
Dispatch object using
createDispatch(portName, SOAPMessage.class, Service.Mode.MESSAGE), both the response and the request
are SOAPMessage objects.
![]() | Note |
|---|---|
When using JAXB objects, both the response and the request can be of any type the provided
|
Example 19.4 shows code for making a synchronous invocation on a remote service
using a DOMSource object.
Example 19.4. Making a Synchronous Invocation Using a Dispatch Object
// Creating a DOMSource Object for the request
DocumentBuilder db = DocumentBuilderFactory.newDocumentBuilder();
Document requestDoc = db.newDocument();
Element root = requestDoc.createElementNS("http://org.apache.cxf/stockExample",
"getStockPrice");
root.setNodeValue("DOW");
DOMSource request = new DOMSource(requestDoc);
// Dispatch disp created previously
DOMSource response = disp.invoke(request);Dispatch objects also support asynchronous invocations. As with the higher level asynchronous APIs discussed in Developing Asynchronous Applications, Dispatch objects can use both the polling approach and the callback approach.
When using the polling approach, the invokeAsync() method returns a
Response<t> object that can be polled to see if the response has arrived.
Example 19.5 shows the signature of the method used to make an asynchronous invocation
using the polling approach.
Example 19.5. The Dispatch.invokeAsync() Method for Polling
Response <T> invokeAsync(T msg)
throws WebServiceException;For detailed information on using the polling approach for asynchronous invocations see Implementing an Asynchronous Client with the Polling Approach.
When using the callback approach, the invokeAsync() method takes an
AsyncHandler implementation that processes the response when it is returned.
Example 19.6 shows the signature of the method used to make an asynchronous
invocation using the callback approach.
Example 19.6. The Dispatch.invokeAsync() Method Using a Callback
Future<?> invokeAsync(T msg,
AsyncHandler<T> handler)
throws WebServiceException;For detailed information on using the callback approach for asynchronous invocations see Implementing an Asynchronous Client with the Callback Approach.
![]() | Note |
|---|---|
As with the synchronous |
When a request does not generate a response, make remote invocations using the
Dispatch object's invokeOneWay().
Example 19.7 shows the signature for this method.
Example 19.7. The Dispatch.invokeOneWay() Method
void invokeOneWay(T msg)
throws WebServiceException;The type of object used to package the request is determined when the
Dispatch object is created. For example if the Dispatch
object is created using createDispatch(portName, DOMSource.class, Service.Mode.PAYLOAD), then the request
is packaged into a DOMSource object.
![]() | Note |
|---|---|
When using JAXB objects, the response and the request can be of any type the provided
|
Example 19.8 shows code for making a oneway invocation on a remote service using a JAXB object.
Example 19.8. Making a One Way Invocation Using a Dispatch Object
// Creating a JAXBContext and an Unmarshaller for the request
JAXBContext jbc = JAXBContext.newInstance("org.apache.cxf.StockExample");
Unmarshaller u = jbc.createUnmarshaller();
// Read the request from disk
File rf = new File("request.xml");
GetStockPrice request = (GetStockPrice)u.unmarshal(rf);
// Dispatch disp created previously
disp.invokeOneWay(request);The Provider interface is a low-level JAX-WS API that allows you to implement a service
provider that works directly with messages as raw XML. The messages are not packaged into JAXB objects before being passed to
an object that implements the Provider interface.
Objects that implement the Provider interface have two messaging modes:
The messaging mode you specify determines the level of messaging detail that is passed to your implementation.
When using message mode, a Provider implementation works
with complete messages. A complete message includes any binding specific headers and wrappers. For example, a
Provider implementation that uses a SOAP binding receives requests as fully specified SOAP
message. Any response returned from the implementation must be a fully specified SOAP message.
To specify that a Provider implementation uses message mode by provide the value
java.xml.ws.Service.Mode.MESSAGE as the value to the
javax.xml.ws.ServiceMode annotation, as shown in
Example 19.9.
Example 19.9. Specifying that a Provider Implementation Uses Message Mode
@WebServiceProvider @ServiceMode(value=Service.Mode.MESSAGE) public class stockQuoteProvider implements Provider<SOAPMessage> { ... }
In payload mode a Provider implementation works with only the payload of a message. For example, a Provider implementation working in payload mode works only with the body of a SOAP message. The binding layer processes any binding level wrappers and headers.
![]() | Tip |
|---|---|
When working with a binding that does not use special wrappers, such as the Fuse Services Framework XML binding, payload mode and message mode provide the same results. |
To specify that a Provider implementation uses payload mode by provide the value
java.xml.ws.Service.Mode.PAYLOAD as the value to the
javax.xml.ws.ServiceMode annotation, as shown in
Example 19.10.
Example 19.10. Specifying that a Provider Implementation Uses Payload Mode
@WebServiceProvider @ServiceMode(value=Service.Mode.PAYLOAD) public class stockQuoteProvider implements Provider<DOMSource> { ... }
![]() | Tip |
|---|---|
If you do not provide a value for the |
Because they are low-level objects, Provider implementations cannot use the same
JAXB generated types as the higher level consumer APIs. Provider implementations work with
the following types of objects:
A Provider implementation can accept and return objects that are derived from the javax.xml.transform.Source interface. Source objects are low level objects that hold XML documents. Each Source implementation provides methods that access the stored XML documents and manipulate its contents. The following objects implement the Source interface:
DOMSourceHolds XML messages as a Document Object Model(DOM) tree. The XML message is stored as a set of
Node objects that are accessed using the getNode() method.
Nodes can be either updated or added to the DOM tree using the setNode() method.
SAXSourceHolds XML messages as a Simple API for XML (SAX) object. SAX objects contain an
InputSource object that holds the raw data and an XMLReader
object that parses the raw data.
StreamSourceHolds XML messages as a data stream. The data stream can be manipulated the same as any other data stream.
If you create your Provider object so that it uses generic
Source objects, Fuse Services Framework returns the messages as
SAXSource objects.
This behavior can be changed using the endpoint's source-preferred-format property. See Configuring Web Service Endpoints for information about configuring the Fuse Services Framework runtime.
![]() | Important |
|---|---|
When using |
Provider implementations can use
javax.xml.soap.SOAPMessage objects when the following conditions are true:
The Provider implementation is using the SOAP binding
The Provider implementation is using message mode
A SOAPMessage object holds a SOAP message. They contain one
SOAPPart object and zero or more AttachmentPart objects. The
SOAPPart object contains the SOAP specific portions of the SOAP message including the SOAP
envelope, any SOAP headers, and the SOAP message body. The AttachmentPart objects contain
binary data that is passed as an attachment.
Provider implementations can use objects that implement the javax.activation.DataSource interface when the following conditions are true:
The implementation is using the HTTP binding
The implementation is using message mode
DataSource objects provide a mechanism for working with MIME typed data from a
variety of sources, including URLs, files, and byte arrays.
The Provider interface is relatively easy to implement. It only has one method,
invoke(), that must be implemented. In addition it has three simple requirements:
An implementation must have the @WebServiceProvider annotation.
An implementation must have a default public constructor.
An implementation must implement a typed version of the Provider interface.
In other words, you cannot implement a Provider<T> interface. You must
implement a version of the interface that uses a concrete data type as listed in
Data Types. For example, you can implement an instance of a
Provider<SAXSource>.
The complexity of implementing the Provider interface is in the logic handling the
request messages and building the proper responses.
Unlike the higher-level SEI based service implementations, Provider implementations
receive requests as raw XML data, and must send responses as raw XML data. This requires that the developer has intimate
knowledge of the messages used by the service being implemented. These details can typically be found in the WSDL document
describing the service.
WS-I Basic Profile provides guidelines about the messages used by services, including:
The root element of a request is based in the value of the name attribute of the
wsdl:operation element that corresponds to the operation that is invoked.
![]() | Warning |
|---|---|
If the service uses doc/literal bare messages, the root element of the request is based on the value of
|
The root element of all messages is namespace qualified.
If the service uses rpc/literal messages, the top-level elements in the messages are not namespace qualified.
![]() | Important |
|---|---|
The children of top-level elements might be namespace qualified, but to be certain you will must check their schema definitions. |
If the service uses rpc/literal messages, none of the top-level elements can be null.
If the service uses doc/literal messages, then the schema definition of the message determines if any of the elements are namespace qualified.
To be recognized by JAX-WS as a service implementation, a Provider implementation must be decorated with the @WebServiceProvider annotation.
Table 19.2 describes the properties that can be set for the
@WebServiceProvider annotation.
Table 19.2. @WebServiceProvider Properties
| Property | Description |
|---|---|
| portName | Specifies the value of the name attribute of the
wsdl:port element that defines the service's endpoint. |
| serviceName | Specifies the value of the name attribute of the
wsdl:service element that contains the service's endpoint. |
| targetNamespace | Specifies the targetname space of the service's WSDL definition. |
| wsdlLocation | Specifies the URI for the WSDL document defining the service. |
All of these properties are optional, and are empty by default. If you leave them empty, Fuse Services Framework creates values using information from the implementation class.
The Provider interface has only one method, invoke(),
that must be implemented. The invoke() method receives the incoming request packaged into
the type of object declared by the type of Provider interface being implemented, and returns
the response message packaged into the same type of object. For example, an implementation of a
Provider<SOAPMessage> interface receives the request as a
SOAPMessage object and returns the response as a SOAPMessage
object.
The messaging mode used by the Provider implementation determines the amount of
binding specific information the request and the response messages contain. Implementations using message mode receive all of
the binding specific wrappers and headers along with the request. They must also add all of the binding specific wrappers and
headers to the response message. Implementations using payload mode only receive the body of the request. The XML document
returned by an implementation using payload mode is placed into the body of the request message.
Example 19.11 shows a Provider implementation that works with SOAPMessage objects in message mode.
Example 19.11. Provider<SOAPMessage> Implementation
import javax.xml.ws.Provider; import javax.xml.ws.Service; import javax.xml.ws.ServiceMode; import javax.xml.ws.WebServiceProvider;@WebServiceProvider(portName="stockQuoteReporterPort" serviceName="stockQuoteReporter")
@ServiceMode(value="Service.Mode.MESSAGE") public class stockQuoteReporterProvider implements Provider<SOAPMessage> {
public stockQuoteReporterProvider() { }
public SOAPMessage invoke(SOAPMessage request) {
SOAPBody requestBody = request.getSOAPBody();
if(requestBody.getElementName.getLocalName.equals("getStockPrice")) {
MessageFactory mf = MessageFactory.newInstance(); SOAPFactory sf = SOAPFactory.newInstance();
SOAPMessage response = mf.createMessage(); SOAPBody respBody = response.getSOAPBody(); Name bodyName = sf.createName("getStockPriceResponse"); respBody.addBodyElement(bodyName); SOAPElement respContent = respBody.addChildElement("price"); respContent.setValue("123.00"); response.saveChanges();
return response; } ... } }
The code in Example 19.11 does the following:
Specifies that the following class implements a | |
Specifies that this | |
Provides the required default public constructor. | |
Provides an implementation of the | |
Extracts the request message from the body of the incoming SOAP message. | |
Checks the root element of the request message to determine how to process the request. | |
Creates the factories required for building the response. | |
Builds the SOAP message for the response. | |
Returns the response as a |
Example 19.12 shows an example of a Provider
implementation using DOMSource objects in payload mode.
Example 19.12. Provider<DOMSource> Implementation
import javax.xml.ws.Provider; import javax.xml.ws.Service; import javax.xml.ws.ServiceMode; import javax.xml.ws.WebServiceProvider;@WebServiceProvider(portName="stockQuoteReporterPort" serviceName="stockQuoteReporter")
@ServiceMode(value="Service.Mode.PAYLOAD") public class stockQuoteReporterProvider implements Provider<DOMSource>
public stockQuoteReporterProvider() { }
public DOMSource invoke(DOMSource request) { DOMSource response = new DOMSource(); ... return response; } }
The code in Example 19.12 does the following:
Specifies that the class implements a | |
Specifies that this | |
Provides the required default public constructor. | |
Provides an implementation of the |
In many instances it is necessary to pass information about a message to other parts of an application. Fuse Services Framework does this using a context mechanism. Contexts are maps that hold properties relating to an outgoing or an incoming message. The properties stored in the context are typically metadata about the message, and the underlying transport used to communicate the message. For example, the transport specific headers used in transmitting the message, such as the HTTP response code or the JMS correlation ID, are stored in the JAX-WS contexts.
The contexts are available at all levels of a JAX-WS application. However, they differ in subtle ways depending upon where in the
message processing stack you are accessing the context. JAX-WS Handler implementations have direct access
to the contexts and can access all properties that are set in them. Service implementations access contexts by having them injected, and
can only access properties that are set in the APPLICATION scope. Consumer implementations can only access properties
that are set in the APPLICATION scope.
Figure 20.1 shows how the context properties pass through Fuse Services Framework. As a message passes through the messaging chain, its associated message context passes along with it.
The message contexts are all implementations of the
javax.xml.ws.handler.MessageContext interface. The
MessageContext interface extends the
java.util.Map<String key, Object value> interface.
Map objects store information as key value pairs.
In a message context, properties are stored as name/value pairs. A property's key is a String that
identifies the property. The value of a property can be any value stored in any Java object. When the value is returned from a message
context, the application must know the type to expect and cast accordingly. For example, if a property's value is stored in a
UserInfo object it is still returned from a message context as an Object object that must
be cast back into a UserInfo object.
Properties in a message context also have a scope. The scope determines where a property can be accessed in the message processing chain.
Properties in a message context are scoped. A property can be in one of the following scopes:
APPLICATIONProperties scoped as APPLICATION are available to JAX-WS Handler implementations,
consumer implementation code, and service provider implementation code. If a handler needs to pass a property to the service provider
implementation, it sets the property's scope to APPLICATION. All properties set from either the consumer
implementation or the service provider implementation contexts are automatically scoped as APPLICATION.
HANDLERProperties scoped as HANDLER are only available to JAX-WS Handler implementations.
Properties stored in a message context from a Handler implementation are scoped as HANDLER
by default.
You can change a property's scope using the message context's setScope() method. Example 20.1 shows the method's signature.
Example 20.1. The MessageContext.setScope() Method
void setScope(String key,
MessageContext.Scope scope)
throws java.lang.IllegalArgumentException;The first parameter specifies the property's key. The second parameter specifies the new scope for the property. The scope can be either:
MessageContext.Scope.APPLICATION
MessageContext.Scope.HANDLER
Classes that implement the JAX-WS Handler interface have direct access to a message's context information. The message's context information is passed into the Handler implementation's handleMessage(), handleFault(), and close() methods.
Handler implementations have access to all of the properties stored in the message context, regardless
of their scope. In addition, logical handlers use a specialized message context called a LogicalMessageContext.
LogicalMessageContext objects have methods that access the contents of the message body.
Service implementations can access properties scoped as APPLICATION from the message context. The service
provider's implementation object accesses the message context through the WebServiceContext object.
For more information see Working with Contexts in a Service Implementation.
Consumer implementations have indirect access to the contents of the message context. The consumer implementation has two separate message contexts:
Request context — holds a copy of the properties used for outgoing requests
Response context — holds a copy of the properties from an incoming response
The dispatch layer transfers the properties between the consumer implementation's message contexts and the message context used by
the Handler implementations.
When a request is passed to the dispatch layer from the consumer implementation, the contents of the request context are copied into
the message context that is used by the dispatch layer. When the response is returned from the service, the dispatch layer processes the
message and sets the appropriate properties into its message context. After the dispatch layer processes a response, it copies all of
the properties scoped as APPLICATION in its message context to the consumer implementation's response context.
For more information see Working with Contexts in a Consumer Implementation.
Context information is made available to service implementations using the WebServiceContext
interface. From the WebServiceContext object you can obtain a MessageContext object
that is populated with the current request's context properties in the application scope. You can manipulate the values of the properties,
and they are propagated back through the response chain.
![]() | Note |
|---|---|
The |
To obtain the message context in a service implementation do the following:
Declare a variable of type WebServiceContext.
Decorate the variable with the javax.annotation.Resource annotation to indicate that the context
information is being injected into the variable.
Obtain the MessageContext object from the WebServiceContext object using
the getMessageContext() method.
![]() | Important |
|---|---|
|
Example 20.2 shows code for obtaining a context object.
Example 20.2. Obtaining a Context Object in a Service Implementation
import javax.xml.ws.*; import javax.xml.ws.handler.*; import javax.annotation.*; @WebServiceProvider public class WidgetServiceImpl { @Resource WebServiceContext wsc; @WebMethod public String getColor(String itemNum) { MessageContext context = wsc.getMessageContext(); } ... }
Once you have obtained the MessageContext object for your implementation, you can access the properties
stored there using the get() method shown in Example 20.3.
![]() | Note |
|---|---|
This |
The key parameter is the string representing the property you want to retrieve from the context. The
get() returns an object that must be cast to the proper type for the property.
Table 20.1 lists a number of the properties that are available in a service implementation's
context.
![]() | Important |
|---|---|
Changing the values of the object returned from the context also changes the value of the property in the context. |
Example 20.4 shows code for getting the name of the WSDL
operation element that represents the invoked operation.
Example 20.4. Getting a Property from a Service's Message Context
import javax.xml.ws.handler.MessageContext; import org.apache.cxf.message.Message; ... // MessageContext context retrieved in a previous example QName wsdl_operation = (QName)context.get(Message.WSDL_OPERATION);
Once you have obtained the MessageContext object for your implementation, you can set properties, and change existing properties, using the put() method shown in Example 20.5.
Example 20.5. The MessageContext.put() Method
V put(K key,
V value)
throws ClassCastException, IllegalArgumentException, NullPointerException;If the property being set already exists in the message context, the put() method replaces the existing value
with the new value and returns the old value. If the property does not already exist in the message context, the
put() method sets the property and returns null.
Example 20.6 shows code for setting the response code for an HTTP request.
Example 20.6. Setting a Property in a Service's Message Context
import javax.xml.ws.handler.MessageContext;
import org.apache.cxf.message.Message;
...
// MessageContext context retrieved in a previous example
context.put(Message.RESPONSE_CODE, new Integer(404));Table 20.1 lists the properties accessible through the context in a service implementation object.
Table 20.1. Properties Available in the Service Implementation Context
| Base Class | |
|---|---|
| Property Name | Description |
org.apache.cxf.message.Message | |
PROTOCOL_HEADERS[a] | Specifies the transport specific header information. The value is stored as a
java.util.Map<String, List<String>>. |
RESPONSE_CODE[a] | Specifies the response code returned to the consumer. The value is stored as an Integer object. |
ENDPOINT_ADDRESS | Specifies the address of the service provider. The value is stored as a String. |
HTTP_REQUEST_METHOD[a] | Specifies the HTTP verb sent with a request. The value is stored as a String. |
PATH_INFO[a] |
Specifies the path of the resource being requested. The value is stored as a The path is the portion of the URI after the hostname and before any query string. For example, if an endpoint's URI is
|
QUERY_STRING[a] |
Specifies the query, if any, attached to the URI used to invoke the request. The value is stored as a
Queries appear at the end of the URI after a |
MTOM_ENABLED | Specifies whether or not the service provider can use MTOM for SOAP attachments. The value is stored as a Boolean. |
SCHEMA_VALIDATION_ENABLED | Specifies whether or not the service provider validates messages against a schema. The value is stored as a Boolean. |
FAULT_STACKTRACE_ENABLED | Specifies if the runtime provides a stack trace along with a fault message. The value is stored as a
Boolean. |
CONTENT_TYPE | Specifies the MIME type of the message. The value is stored as a String. |
BASE_PATH |
Specifies the path of the resource being requested. The value is stored as a The path is the portion of the URI after the hostname and before any query string. For example, if an endpoint's URL is
|
ENCODING | Specifies the encoding of the message. The value is stored as a String. |
FIXED_PARAMETER_ORDER | Specifies whether the parameters must appear in the message in a particular order. The value is stored as a Boolean. |
MAINTAIN_SESSION | Specifies if the consumer wants to maintain the current session for future requests. The value is stored as a Boolean. |
WSDL_DESCRIPTION[a] | Specifies the WSDL document that defines the service being implemented. The value is stored as a
org.xml.sax.InputSource object. |
WSDL_SERVICE[a] | Specifies the qualified name of the wsdl:service element that defines the service being
implemented. The value is stored as a QName. |
WSDL_PORT[a] | Specifies the qualified name of the wsdl:port element that defines the endpoint used to access the
service. The value is stored as a QName. |
WSDL_INTERFACE[a] | Specifies the qualified name of the wsdl:portType element that defines the service being
implemented. The value is stored as a QName. |
WSDL_OPERATION[a] | Specifies the qualified name of the wsdl:operation element that corresponds to the operation
invoked by the consumer. The value is stored as a QName. |
javax.xml.ws.handler.MessageContext | |
MESSAGE_OUTBOUND_PROPERTY | Specifies if a message is outbound. The value is stored as a Boolean. true specifies that a message is outbound. |
INBOUND_MESSAGE_ATTACHMENTS |
Contains any attachments included in the request message. The value is stored as a The key value for the map is the MIME Content-ID for the header. |
OUTBOUND_MESSAGE_ATTACHMENTS |
Contains any attachments for the response message. The value is stored as a The key value for the map is the MIME Content-ID for the header. |
WSDL_DESCRIPTION | Specifies the WSDL document that defines the service being implemented. The value is stored as a
org.xml.sax.InputSource object. |
WSDL_SERVICE | Specifies the qualified name of the wsdl:service element that defines the service being
implemented. The value is stored as a QName. |
WSDL_PORT | Specifies the qualified name of the wsdl:port element that defines the endpoint used to access the
service. The value is stored as a QName. |
WSDL_INTERFACE | Specifies the qualified name of the wsdl:portType element that defines the service being
implemented. The value is stored as a QName. |
WSDL_OPERATION | Specifies the qualified name of the wsdl:operation element that corresponds to the operation
invoked by the consumer. The value is stored as a QName. |
HTTP_RESPONSE_CODE | Specifies the response code returned to the consumer. The value is stored as an Integer object. |
HTTP_REQUEST_HEADERS | Specifies the HTTP headers on a request. The value is stored as a
java.util.Map<String, List<String>>. |
HTTP_RESPONSE_HEADERS | Specifies the HTTP headers for the response. The value is stored as a
java.util.Map<String, List<String>>. |
HTTP_REQUEST_METHOD | Specifies the HTTP verb sent with a request. The value is stored as a String. |
SERVLET_REQUEST | Contains the servlet's request object. The value is stored as a javax.servlet.http.HttpServletRequest. |
SERVLET_RESPONSE | Contains the servlet's response object. The value is stored as a javax.servlet.http.HttpResponse. |
SERVLET_CONTEXT | Contains the servlet's context object. The value is stored as a javax.servlet.ServletContext. |
PATH_INFO |
Specifies the path of the resource being requested. The value is stored as a The path is the portion of the URI after the hostname and before any query string. For example, if an endpoint's URL is
|
QUERY_STRING |
Specifies the query, if any, attached to the URI used to invoke the request. The value is stored as a
Queries appear at the end of the URI after a |
REFERENCE_PARAMETERS | Specifies the WS-Addressing reference parameters. This includes all of the SOAP headers whose wsa:IsReferenceParameter attribute is set to true. The value is stored as a java.util.List. |
org.apache.cxf.transport.jms.JMSConstants | |
JMS_SERVER_HEADERS | Contains the JMS message headers. For more information see Working with JMS Message Properties. |
[a] When using HTTP this property is the same as the standard JAX-WS defined property. | |
Consumer implementations have access to context information through the BindingProvider interface. The
BindingProvider instance holds context information in two separate contexts:
The request context enables you to set properties that affect outbound messages. Request context properties are applied to a specific port instance and, once set, the properties affect every subsequent operation invocation made on the port, until such time as a property is explicitly cleared. For example, you might use a request context property to set a connection timeout or to initialize data for sending in a header.
The response context enables you to read the property values set by the response to the last operation invocation made from the current thread. Response context properties are reset after every operation invocation. For example, you might access a response context property to read header information received from the last inbound message.
![]() | Important |
|---|---|
Only information that is placed in the application scope of a message context can be accessed by the consumer implementation. |
Contexts are obtained using the javax.xml.ws.BindingProvider interface. The BindingProvider
interface has two methods for obtaining a context:
getRequestContext()The getRequestContext() method, shown in Example 20.7, returns the request
context as a Map object. The returned Map object can be used to directly manipulate the contents of the context.
getResponseContext()The getResponseContext(), shown in Example 20.8, returns
the response context as a Map object. The returned Map object's contents reflect the
state of the response context's contents from the most recent successful request on a remote service made in the current
thread.
Since proxy objects implement the BindingProvider interface, a
BindingProvider object can be obtained by casting a proxy object. The contexts obtained from the
BindingProvider object are only valid for operations invoked on the proxy object used to create it.
Example 20.9 shows code for obtaining the request context for a proxy.
Example 20.9. Getting a Consumer's Request Context
// Proxy widgetProxy obtained previously
BindingProvider bp = (BindingProvider)widgetProxy;
Map<String, Object> responseContext = bp.getResponseContext();
Consumer contexts are stored in java.util.Map<String, Object> objects. The map has keys that are
String objects and values that contain arbitrary objects. Use java.util.Map.get() to access an entry
in the map of response context properties.
To retrieve a particular context property, ContextPropertyName, use the code shown in Example 20.10.
Example 20.10. Reading a Response Context Property
// Invoke an operation. port.SomeOperation(); // Read response context property. java.util.Map<String, Object> responseContext = ((javax.xml.ws.BindingProvider)port).getResponseContext();PropertyTypepropValue = (PropertyType) responseContext.get(ContextPropertyName);
Consumer contexts are hash maps stored in java.util.Map<String, Object> objects. The map has keys that
are String objects and values that are arbitrary objects. To set a property in a context use the
java.util.Map.put() method.
![]() | Tip |
|---|---|
While you can set properties in both the request context and the response context, only the changes made to the request context have any impact on message processing. The properties in the response context are reset when each remote invocation is completed on the current thread. |
The code shown in Example 20.11 changes the address of the target service provider by setting the value of the
BindingProvider.ENDPOINT_ADDRESS_PROPERTY.
Example 20.11. Setting a Request Context Property
// Set request context property.
java.util.Map<String, Object> requestContext =
((javax.xml.ws.BindingProvider)port).getRequestContext();
requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, "http://localhost:8080/widgets");
// Invoke an operation.
port.SomeOperation();![]() | Important |
|---|---|
Once a property is set in the request context its value is used for all subsequent remote invocations. You can change the value and the changed value will then be used. |
Fuse Services Framework supports the following context properties in consumer implementations:
Table 20.2. Consumer Context Properties
| Base Class | |
|---|---|
| Property Name | Description |
javax.xml.ws.BindingProvider | |
ENDPOINT_ADDRESS_PROPERTY | Specifies the address of the target service. The value is stored as a String. |
USERNAME_PROPERTY[a] | Specifies the username used for HTTP basic authentication. The value is stored as a String. |
PASSWORD_PROPERTY[b] | Specifies the password used for HTTP basic authentication. The value is stored as a String. |
SESSION_MAINTAIN_PROPERTY[c] | Specifies if the client wants to maintain session information. The value is stored as a Boolean
object. |
| org.apache.cxf.ws.addressing.JAXWSAConstants | |
CLIENT_ADDRESSING_PROPERTIES | Specifies the WS-Addressing information used by the consumer to contact the desired service provider. The value is stored as a
org.apache.cxf.ws.addressing.AddressingProperties. |
| org.apache.cxf.transports.jms.context.JMSConstants | |
JMS_CLIENT_REQUEST_HEADERS | Contains the JMS headers for the message. For more information see Working with JMS Message Properties. |
[a] This property is overridden by the username defined in the HTTP security settings. [b] This property is overridden by the password defined in the HTTP security settings. [c] The Fuse Services Framework ignores this property. | |
The Fuse Services Framework JMS transport has a context mechanism that can be used to inspect a JMS message's properties. The context mechanism can also be used to set a JMS message's properties.
Consumers and services use different context mechanisms to access the JMS message header properties. However, both mechanisms return the header properties as a org.apache.cxf.transports.jms.context.JMSMessageHeadersType object.
To get the JMS message header properties from the WebServiceContext object, do the following:
Obtain the context as described in Obtaining a context.
Get the message headers from the message context using the message context's get() method with the parameter org.apache.cxf.transports.jms.JMSConstants.JMS_SERVER_HEADERS.
Example 20.12 shows code for getting the JMS message headers from a service's message context:
Example 20.12. Getting JMS Message Headers in a Service Implementation
import org.apache.cxf.transport.jms.JMSConstants;
import org.apache.cxf.transports.jms.context.JMSMessageHeadersType;
@WebService(serviceName = "HelloWorldService",
portName = "HelloWorldPort",
endpointInterface = "org.apache.cxf.hello_world_jms.HelloWorldPortType",
targetNamespace = "http://cxf.apache.org/hello_world_jms")
public class GreeterImplTwoWayJMS implements HelloWorldPortType
{
@Resource
protected WebServiceContext wsContext;
...
@WebMethod
public String greetMe(String me)
{
MessageContext mc = wsContext.getMessageContext();
JMSMessageHeadersType headers = (JMSMessageHeadersType) mc.get(JMSConstants.JMS_SERVER_HEADERS);
...
}
...
}Once a message is successfully retrieved from the JMS transport you can inspect the JMS header properties using the consumer's response context. In addition, you can see how long the client waits for a response before timing out.
You can To get the JMS message headers from a consumer's response context do the following:
Get the response context as described in Obtaining a context.
Get the JMS message header properties from the response context using the context's get() method with org.apache.cxf.transports.jms.JMSConstants.JMS_CLIENT_RESPONSE_HEADERS as the parameter.
Example 20.13 shows code for getting the JMS message header properties from a consumer's response context.
Example 20.13. Getting the JMS Headers from a Consumer Response Header
import org.apache.cxf.transports.jms.context.*; // Proxy greeter initialized previouslyBindingProvider bp = (BindingProvider)greeter;
Map<String, Object> responseContext = bp.getResponseContext();
JMSMessageHeadersType responseHdr = (JMSMessageHeadersType) responseContext.get(JMSConstants.JMS_CLIENT_REQUEST_HEADERS); ... }
The code in Example 20.13 does the following:
Table 20.3 lists the standard properties in the JMS header that you can inspect.
Table 20.3. JMS Header Properties
| Property Name | Property Type | Getter Method |
|---|---|---|
| Correlation ID | string |
getJMSCorralationID()
|
| Delivery Mode | int |
getJMSDeliveryMode()
|
| Message Expiration | long |
getJMSExpiration()
|
| Message ID | string |
getJMSMessageID()
|
| Priority | int |
getJMSPriority()
|
| Redelivered | boolean |
getJMSRedlivered()
|
| Time Stamp | long |
getJMSTimeStamp()
|
| Type | string |
getJMSType()
|
| Time To Live | long | getTimeToLive() |
In addition, you can inspect any optional properties stored in the JMS header using JMSMessageHeadersType.getProperty(). The optional properties are returned as a List of org.apache.cxf.transports.jms.context.JMSPropertyType. Optional properties are stored as name/value pairs.
Example 20.14 shows code for inspecting some of the JMS properties using the response context.
Example 20.14. Reading the JMS Header Properties
// JMSMessageHeadersType messageHdr retrieved previouslySystem.out.println("Correlation ID: "+messageHdr.getJMSCorrelationID());
System.out.println("Message Priority: "+messageHdr.getJMSPriority());
System.out.println("Redelivered: "+messageHdr.getRedelivered()); JMSPropertyType prop = null;
List<JMSPropertyType> optProps = messageHdr.getProperty();
Iterator<JMSPropertyType> iter = optProps.iterator();
while (iter.hasNext()) { prop = iter.next(); System.out.println("Property name: "+prop.getName()); System.out.println("Property value: "+prop.getValue()); }
The code in Example 20.14 does the following:
Prints the value of the message's correlation ID. | |
Prints the value of the message's priority property. | |
Prints the value of the message's redelivered property. | |
Gets the list of the message's optional header properties. | |
Gets an | |
Iterates through the list of optional properties and prints their name and value. |
Using the request context in a consumer endpoint, you can set a number of the JMS message header properties and the consumer endpoint's timeout value. These properties are valid for a single invocation. You must reset them each time you invoke an operation on the service proxy.
![]() | Note |
|---|---|
You cannot set header properties in a service. |
Table 20.4 lists the properties in the JMS header that can be set using the consumer endpoint's request context.
Table 20.4. Settable JMS Header Properties
| Property Name | Property Type | Setter Method |
|---|---|---|
| Correlation ID | string |
setJMSCorralationID()
|
| Delivery Mode | int |
setJMSDeliveryMode()
|
| Priority | int |
setJMSPriority()
|
| Time To Live | long |
setTimeToLive()
|
To set these properties do the following:
Create an org.apache.cxf.transports.jms.context.JMSMessageHeadersType object.
Populate the values you want to set using the appropriate setter methods described in Table 20.4.
Set the values to the request context by calling the request context's put() method using
org.apache.cxf.transports.jms.JMSConstants.JMS_CLIENT_REQUEST_HEADERS as the first argument, and the new
JMSMessageHeadersType object as the second argument.
You can also set optional properties to the JMS header. Optional JMS header properties are stored in the
JMSMessageHeadersType object that is used to set the other JMS header properties. They are stored as a
List object containing org.apache.cxf.transports.jms.context.JMSPropertyType objects.
To add optional properties to the JMS header do the following:
Create a JMSPropertyType object.
Set the property's name field using setName().
Set the property's value field using setValue().
Add the property to the JMS message header using
JMSMessageHeadersType.getProperty().add(JMSPropertyType).
Repeat the procedure until all of the properties have been added to the message header.
In addition to the JMS header properties, you can set the amount of time a consumer endpoint waits for a response before timing
out. You set the value by calling the request context's put() method with
org.apache.cxf.transports.jms.JMSConstants.JMS_CLIENT_RECEIVE_TIMEOUT as the first argument and a
long representing the amount of time in milliseconds that you want the consumer to wait as the second argument.
Example 20.15 shows code for setting some of the JMS properties using the request context.
Example 20.15. Setting JMS Properties using the Request Context
import org.apache.cxf.transports.jms.context.*; // Proxy greeter initialized previouslyInvocationHandler handler = Proxy.getInvocationHandler(greeter); BindingProvider bp= null;
if (handler instanceof BindingProvider) {
bp = (BindingProvider)handler;
Map<String, Object> requestContext = bp.getRequestContext();
JMSMessageHeadersType requestHdr = new JMSMessageHeadersType();
requestHdr.setJMSCorrelationID("WithBob");
requestHdr.setJMSExpiration(3600000L);
JMSPropertyType prop = new JMSPropertyType;
prop.setName("MyProperty"); prop.setValue("Bluebird");
requestHdr.getProperty().add(prop);
requestContext.put(JMSConstants.CLIENT_REQUEST_HEADERS, requestHdr);
requestContext.put(JMSConstants.CLIENT_RECEIVE_TIMEOUT, new Long(1000)); }
The code in Example 20.15 does the following:
Gets the | |
Checks to see if the | |
Casts the returned | |
Gets the request context. | |
Creates a | |
Sets the Correlation ID. | |
Sets the Expiration property to 60 minutes. | |
Creates a new | |
Sets the values for the optional property. | |
Adds the optional property to the message header. | |
Sets the JMS message header values into the request context. | |
Sets the client receive timeout property to 1 second. |
When a service proxy invokes an operation on a service, the operation's parameters are passed to Fuse Services Framework where they are built into a message and placed on the wire. When the message is received by the service, Fuse Services Framework reads the message from the wire, reconstructs the message, and then passes the operation parameters to the application code responsible for implementing the operation. When the application code is finished processing the request, the reply message undergoes a similar chain of events on its trip to the service proxy that originated the request. This is shown in Figure 21.1.
JAX-WS defines a mechanism for manipulating the message data between the application level code and the network. For example, you might want the message data passed over the open network to be encrypted using a proprietary encryption mechanism. You could write a JAX-WS handler that encrypted and decrypted the data. Then you could insert the handler into the message processing chains of all clients and servers.
As shown in Figure 21.2, the handlers are placed in a chain that is traversed between the application level code and the transport code that places the message onto the network.
The JAX-WS specification defines two basic handler types:
Logical handlers can process the message payload and the properties stored in the message context. For example, if the application uses pure XML messages, the logical handlers have access to the entire message. If the application uses SOAP messages, the logical handlers have access to the contents of the SOAP body. They do not have access to either the SOAP headers or any attachments unless they were placed into the message context.
Logical handlers are placed closest to the application code on the handler chain. This means that they are executed first when a message is passed from the application code to the transport. When a message is received from the network and passed back to the application code, the logical handlers are executed last.
Protocol handlers can process the entire message received from the network and the properties stored in the message context. For example, if the application uses SOAP messages, the protocol handlers would have access to the contents of the SOAP body, the SOAP headers, and any attachments.
Protocol handlers are placed closest to the transport on the handler chain. This means that they are executed first when a message is received from the network. When a message is sent to the network from the application code, the protocol handlers are executed last.
![]() | Tip |
|---|---|
The only protocol handler supported by Fuse Services Framework is specific to SOAP. |
The differences between the two handler types are very subtle and they share a common base interface. Because of their common parentage, logical handlers and protocol handlers share a number of methods that must be implemented, including:
The handleMessage() method is the central method in any handler. It is the method responsible for
processing normal messages.
handleFault() is the method responsible for processing fault messages.
close() is called on all executed handlers in a handler chain when a message has reached
the end of the chain. It is used to clean up any resources consumed during message processing.
The differences between the implementation of a logical handler and the implementation of a protocol handler revolve around the following:
The specific interface that is implemented
All handlers implement an interface that derives from the Handler interface. Logical handlers
implement the LogicalHandler interface. Protocol handlers implement protocol specific extensions
of the Handler interface. For example, SOAP handlers implement the
SOAPHandler interface.
The amount of information available to the handler
Protocol handlers have access to the contents of messages and all of the protocol specific information that is packaged with the message content. Logical handlers can only access the contents of the message. Logical handlers have no knowledge of protocol details.
To add a handler to an application you must do the following:
Determine whether the handler is going to be used on the service providers, the consumers, or both.
Determine which type of handler is the most appropriate for the job.
Implement the proper interface.
To implement a logical handler see Implementing a Logical Handler.
To implement a protocol handler see Implementing a Protocol Handler.
Configure your endpoint(s) to use the handlers.
Logical handlers implement the javax.xml.ws.handler.LogicalHandler interface.
The LogicalHandler interface, shown in Example 21.1
passes a LogicalMessageContext object to the handleMessage() method
and the handleFault() method. The context object provides access to the body
of the message and to any properties set into the message exchange's context.
Example 21.1. LogicalHandler Synopsis
public interface LogicalHandler extends Handler
{
boolean handleMessage(LogicalMessageContext context);
boolean handleFault(LogicalMessageContext context);
void close(LogicalMessageContext context);
}To implement a logical hander you do the following:
Implement any initialization logic required by the handler.
Implement the message handling logic.
Implement the fault handling logic.
Implement the logic for closing the handler when it is finished.
Implement any logic for cleaning up the handler's resources before it is destroyed.
Normal message processing is handled by the handleMessage() method.
The handleMessage() method receives a LogicalMessageContext
object that provides access to the message body and any properties stored in the message context.
The handleMessage() method returns either true or
false depending on how message processing is to continue. It can also throw an exception.
The LogicalMessageContext object passed into logical message handlers allows access
to the message body using the context's getMessage() method. The
getMessage() method, shown in Example 21.2,
returns the message payload as a LogicalMessage object.
Example 21.2. Method for Getting the Message Payload in a Logical Handler
LogicalMessage getMessage();Once you have the LogicalMessage object, you can use it to manipulate the message body.
The LogicalMessage interface, shown in Example 21.3,
has getters and setters for working with the actual message body.
Example 21.3. Logical Message Holder
LogicalMessage {Source getPayload();Object getPayload(JAXBContext context);void setPayload(Object payload,
JAXBContext context);void setPayload(Source payload);
}
![]() | Important |
|---|---|
The contents of the message payload are determined by the type of binding in use. The SOAP binding only allows access to the SOAP body of the message. The XML binding allows access to the entire message body. |
One pair of getters and setters of the logical message work with the message payload as a
javax.xml.transform.dom.DOMSource object.
The getPayload() method that has no parameters returns the message payload as
a DOMSource object. The returned object is the actual message payload. Any changes made
to the returned object change the message body immediately.
You can replace the body of the message with a DOMSource object using the
setPayload() method that takes the single Source
object.
The other pair of getters and setters allow you to work with the message payload as a JAXB object. They use a
JAXBContext object to transform the message payload into JAXB objects.
To use the JAXB objects you do the following:
Get a JAXBContext object that can manage the data types in the message body.
For information on creating a JAXBContext object see Using A JAXBContext Object.
Get the message body as shown in Example 21.4.
Example 21.4. Getting the Message Body as a JAXB Object
JAXBContext jaxbc = JAXBContext(myObjectFactory.class);
Object body = message.getPayload(jaxbc);Cast the returned object to the proper type.
Manipulate the message body as needed.
Put the updated message body back into the context as shown in Example 21.5.
The logical message context passed into a logical handler is an instance of the application's message context and can access
all of the properties stored in it. Handlers have access to properties at both the APPLICATION scope and the
HANDLER scope.
Like the application's message context, the logical message context is a subclass of Java Map.
To access the properties stored in the context, you use the get() method and put()
method inherited from the Map interface.
By default, any properties you set in the message context from inside a logical handler are assigned a scope of
HANDLER. If you want the application code to be able to access the property you need to use the context's
setScope() method to explicitly set the property's scope to APPLICATION.
For more information on working with properties in the message context see Understanding Contexts.
It is often important to know the direction a message is passing through the handler chain. For example, you would want to retrieve a security token from incoming requests and attach a security token to an outgoing response.
The direction of the message is stored in the message context's outbound message property. You retrieve the outbound message property from the
message context using the MessageContext.MESSAGE_OUTBOUND_PROPERTY key as shown in Example 21.6.
Example 21.6. Getting the Message's Direction from the SOAP Message Context
Boolean outbound; outbound = (Boolean)smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
The property is stored as a Boolean object. You can use the object's booleanValue()
method to determine the property's value. If the property is set to true, the message is outbound. If the property is set to
false the message is inbound.
How the handleMessage() method completes its message processing has a direct impact on how message processing proceeds.
It can complete by doing one of the following actions:
Return true—Returning true signals to the Fuse Services Framework runtime that message
processing should continue normally. The next handler, if any, has its handleMessage() invoked.
Return false—Returning false signals to the Fuse Services Framework runtime that normal
message processing must stop. How the runtime proceeds depends on the message exchange pattern in use for the
current message.
For request-response message exchanges the following happens:
The direction of message processing is reversed.
For example, if a request is being processed by a service provider, the message stops progressing toward the service's implementation object. Instead, it is sent back towards the binding for return to the consumer that originated the request.
Any message handlers that reside along the handler chain in the new processing direction have their handleMessage() method
invoked in the order in which they reside in the chain.
When the message reaches the end of the handler chain it is dispatched.
For one-way message exchanges the following happens:
Message processing stops.
All previously invoked message handlers have their close() method invoked.
The message is dispatched.
Throw a ProtocolException exception—Throwing a
ProtocolException exception, or a subclass of this exception, signals the Fuse Services Framework runtime
that fault message processing is beginning. How the runtime proceeds depends on the message exchange pattern in use for the
current message.
For request-response message exchanges the following happens:
If the handler has not already created a fault message, the runtime wraps the message in a fault message.
The direction of message processing is reversed.
For example, if a request is being processed by a service provider, the message stops progressing toward the service's implementation object. Instead, it is sent back towards the binding for return to the consumer that originated the request.
Any message handlers that reside along the handler chain in the new processing direction have their handleFault() method
invoked in the order in which they reside in the chain.
When the fault message reaches the end of the handler chain it is dispatched.
For one-way message exchanges the following happens:
If the handler has not already created a fault message, the runtime wraps the message in a fault message.
Message processing stops.
All previously invoked message handlers have their close() method invoked.
The fault message is dispatched.
Throw any other runtime exception—Throwing a runtime exception other than a
ProtocolException exception signals the Fuse Services Framework runtime that message processing is to stop. All
previously invoked message handlers have the close() method invoked and the exception is dispatched. If
the message is part of a request-response message exchange, the exception is dispatched so that it is returned to the consumer
that originated the request.
Example 21.7 shows an implementation of handleMessage() message
for a logical message handler that is used by a service consumer. It processes requests before they are sent to the service
provider.
Example 21.7. Logical Message Handler Message Processing
public class SmallNumberHandler implements LogicalHandler<LogicalMessageContext>
{
public final boolean handleMessage(LogicalMessageContext messageContext)
{
try
{
boolean outbound = (Boolean)messageContext.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (outbound)
{
LogicalMessage msg = messageContext.getMessage();
JAXBContext jaxbContext = JAXBContext.newInstance(ObjectFactory.class);
Object payload = msg.getPayload(jaxbContext);
if (payload instanceof JAXBElement)
{
payload = ((JAXBElement)payload).getValue();
}
if (payload instanceof AddNumbers)
{
AddNumbers req = (AddNumbers)payload;
int a = req.getArg0();
int b = req.getArg1();
int answer = a + b;
if (answer < 20)
{
AddNumbersResponse resp = new AddNumbersResponse();
resp.setReturn(answer);
msg.setPayload(new ObjectFactory().createAddNumbersResponse(resp),
jaxbContext);
return false;
}
}
else
{
throw new WebServiceException("Bad Request");
}
}
return true;
}
catch (JAXBException ex)
{
throw new ProtocolException(ex);
}
}
...
}The code in Example 21.7 does the following:
Checks if the message is an outbound request. If the message is an outbound request, the handler does additional message processing. | |
Gets the | |
Gets the actual message payload as a JAXB object. | |
Checks to make sure the request is of the correct type. If it is, the handler continues processing the message. | |
Checks the value of the sum. If it is less than the threshold of 20 then it builds a response and returns it to the client. | |
Builds the response. | |
Returns | |
Throws a runtime exception if the message is not of the correct type. This exception is returned to the client. | |
Returns Message processing continues normally. | |
Throws a The exception is passed back to the client after it is processed by the |
Protocol handlers are specific to the protocol in use. Fuse Services Framework provides the SOAP protocol handler as specified by JAX-WS. A SOAP protocol handler
implements the javax.xml.ws.handler.soap.SOAPHandler interface.
The SOAPHandler interface, shown in Example 21.8, uses a SOAP specific message
context that provides access to the message as a SOAPMessage object. It also allows you to access the SOAP
headers.
Example 21.8. SOAPHandler Synopsis
public interface SOAPHandler extends Handler
{
boolean handleMessage(SOAPMessageContext context);
boolean handleFault(SOAPMessageContext context);
void close(SOAPMessageContext context);
Set<QName> getHeaders()
}In addition to using a SOAP specific message context, SOAP protocol handlers require that you implement an additional method called
getHeaders(). This additional method returns the QNames of the header blocks the handler can process.
To implement a logical hander do the following:
Implement any initialization logic required by the handler.
Implement the message handling logic.
Implement the fault handling logic.
Implement the getHeaders() method.
Implement the logic for closing the handler when it is finished.
Implement any logic for cleaning up the handler's resources before it is destroyed.
The getHeaders(), shown in Example 21.9, method informs the Fuse Services Framework runtime what SOAP headers the handler is responsible for
processing. It returns the QNames of the outer element of each SOAP header the handler understands.
For many cases simply returning null is sufficient. However, if the application uses the
mustUnderstand attribute of any of the SOAP headers, then it is important to specify the headers understood
by the application's SOAP handlers. The runtime checks the set of SOAP headers that all of the registered handlers understand against the
list of headers with the mustUnderstand attribute set to true. If any of the
flagged headers are not in the list of understood headers, the runtime rejects the message and throws a SOAP must
understand exception.
Normal message processing is handled by the handleMessage() method.
The handleMessage() method receives a SOAPMessageHandler
object that provides access to the message body as a SOAPMessage object and the SOAP headers associated
with the message. In addition, the context provides access to any properties stored in the message context.
The handleMessage() method returns either true or false
depending on how message processing is to continue. It can also throw an exception.
You can get the SOAP message using the SOAP message context's getMessage() method. It returns the
message as a live SOAPMessage object. Any changes to the message in the handler are automatically reflected in the
message stored in the context.
If you wish to replace the existing message with a new one, you can use the context's setMessage() method.
The setMessage() method takes a SOAPMessage object.
You can access the SOAP message's headers using the SOAPMessage object's
getHeader() method. This will return the SOAP header as a SOAPHeader object that
you will need to inspect to find the header elements you wish to process.
The SOAP message context provides a getHeaders() method, shown in
Example 21.10, that will return an array containing JAXB objects for the specified SOAP headers.
Example 21.10. The SOAPMessageContext.getHeaders() Method
Ojbect[] getHeaders(QName header,
JAXBContext context,
boolean allRoles);You specify the headers using the QName of their element. You can further limit the headers that are returned by setting the
allRoles parameter to false. That instructs the runtime to only return the SOAP headers
that are applicable to the active SOAP roles.
If no headers are found, the method returns an empty array.
For more information about instantiating a JAXBContext object see Using A JAXBContext Object.
The SOAP message context passed into a logical handler is an instance of the application's message context and can access
all of the properties stored in it. Handlers have access to properties at both the APPLICATION scope and the
Handler scope.
Like the application's message context, the SOAP message context is a subclass of Java Map.
To access the properties stored in the context, you use the get() method and put()
method inherited from the Map interface.
By default, any properties you set in the context from inside a logical handler will be assigned a scope of HANDLER.
If you want the application code to be able to access the property you need to use the context's setScope() method to
explicitly set the property's scope to APPLICATION.
For more information on working with properties in the message context see Understanding Contexts.
It is often important to know the direction a message is passing through the handler chain. For example, you would want to add headers to an outgoing message and strip headers from an incoming message.
The direction of the message is stored in the message context's outbound message property. You retrieve the outbound message property from the
message context using the MessageContext.MESSAGE_OUTBOUND_PROPERTY key as shown in Example 21.11.
Example 21.11. Getting the Message's Direction from the SOAP Message Context
Boolean outbound; outbound = (Boolean)smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
The property is stored as a Boolean object. You can use the object's booleanValue()
method to determine the property's value. If the property is set to true, the message is outbound. If the property is set to
false the message is inbound.
How the handleMessage() method completes its message processing has a direct impact on how message processing proceeds.
It can complete by doing one of the following actions:
return true—Returning true signals to the Fuse Services Framework runtime that message processing should continue normally. The next handler, if any, has
its handleMessage() invoked.
return false—Returning false signals to the Fuse Services Framework runtime that normal message processing is to stop. How the runtime proceeds depends
on the message exchange pattern in use for the current message.
For request-response message exchanges the following happens:
The direction of message processing is reversed.
For example, if a request is being processed by a service provider, the message will stop progressing toward the service's implementation object. It will instead be sent back towards the binding for return to the consumer that originated the request.
Any message handlers that reside along the handler chain in the new processing direction have their handleMessage() method
invoked in the order in which they reside in the chain.
When the message reaches the end of the handler chain it is dispatched.
For one-way message exchanges the following happens:
Message processing stops.
All previously invoked message handlers have their close() method invoked.
The message is dispatched.
throw a ProtocolException exception—Throwing a
ProtocolException exception, or a subclass of this exception, signals the Fuse Services Framework runtime that
fault message processing is to start. How the runtime proceeds depends on the message exchange pattern in use for the current message.
For request-response message exchanges the following happens:
If the handler has not already created a fault message, the runtime wraps the message in a fault message.
The direction of message processing is reversed.
For example, if a request is being processed by a service provider, the message will stop progressing toward the service's implementation object. It will be sent back towards the binding for return to the consumer that originated the request.
Any message handlers that reside along the handler chain in the new processing direction have their handleFault() method
invoked in the order in which they reside in the chain.
When the fault message reaches the end of the handler chain it is dispatched.
For one-way message exchanges the following happens:
If the handler has not already created a fault message, the runtime wraps the message in a fault message.
Message processing stops.
All previously invoked message handlers have their close() method invoked.
The fault message is dispatched.
throw any other runtime exception—Throwing a runtime exception other than a ProtocolException exception signals the Fuse Services Framework runtime that message
processing is to stop. All previously invoked message handlers have the close() method invoked and the exception is dispatched.
If the message is part of a request-response message exchange the exception is dispatched so that it is returned to the consumer that originated the request.
Example 21.12 shows a handleMessage() implementation that prints the
SOAP message to the screen.
Example 21.12. Handling a Message in a SOAP Handler
public boolean handleMessage(SOAPMessageContext smc)
{
PrintStream out;
Boolean outbound = (Boolean)smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (outbound.booleanValue())
{
out.println("\nOutbound message:");
}
else
{
out.println("\nInbound message:");
}
SOAPMessage message = smc.getMessage();
message.writeTo(out);
out.println();
return true;
}The code in Example 21.12 does the following:
When the runtime creates an instance of a handler, it creates all of the resources the hander needs to process messages. While you can place all of the logic for doing this in the handler's constructor, it may not be the most appropriate place. The handler framework performs a number of optional steps when it instantiates a handler. You can add resource injection and other initialization logic that will be executed during the optional steps.
![]() | Tip |
|---|---|
You do not have to provide any initialization methods for a handler. |
The Fuse Services Framework runtime initializes a handler in the following manner:
The handler's constructor is called.
Any resources that are specified by the @Resource
annotation are injected.
The method decorated with @PostConstruct annotation, if it is
present, is called.
![]() | Note |
|---|---|
Methods decorated with the |
The handler is place in the Ready state.
Handlers use the handleFault() method for processing fault messages when a
ProtocolException exception is thrown during message processing.
The handleFault() method receives either a LogicalMessageContext object or
SOAPMessageContext object depending on the type of handler. The received context gives the handler's implementation
access to the message payload.
The handleFault() method returns either true or false, depending
on how fault message processing is to proceed. It can also throw an exception.
The context object received by the handleFault() method is similar to the one received by the
handleMessage() method. You use the context's getMessage() method
to access the message payload in the same way. The only difference is the payload contained in the context.
For more information on working with a LogicalMessageContext see Handling Messages in a Logical Handler.
For more information on working with a SOAPMessageContext see Handling Messages in a SOAP Handler.
How the handleFault() method completes its message processing has a direct impact on how message
processing proceeds. It completes by performing one of the following actions:
trueReturning true signals that fault processing should continue normally. The
handleFault() method of the next handler in the chain will be invoked.
falseReturning false signals that fault processing stops. The
close() method of the handlers that were invoked in processing the current
message are invoked and the fault message is dispatched.
Throwing an exception stops fault message processing. The close() method of the
handlers that were invoked in processing the current message are invoked and the exception is dispatched.
Example 21.13 shows an implementation of handleFault() that prints the message body to the screen.
Example 21.13. Handling a Fault in a Message Handler
public final boolean handleFault(LogicalMessageContext messageContext)
{
System.out.println("handleFault() called with message:");
LogicalMessage msg=messageContext.getMessage();
System.out.println(msg.getPayload());
return true;
}When a handler chain is finished processing a message, the runtime calls each executed handler's close() method. This is the appropriate
place to clean up any resources that were used by the handler during message processing or resetting any properties to a default state.
If a resource needs to persist beyond a single message exchange, you should not clean it up during in the handler's close() method.
The runtime releases a handler when the service or service proxy to which the handler is bound is shutdown. The runtime will invoke an optional release method before invoking the handler's destructor. This optional release method can be used to release any resources used by the handler or perform other actions that would not be appropriate in the handler's destructor.
![]() | Tip |
|---|---|
You do not have to provide any clean-up methods for a handler. |
![]() | Important |
|---|---|
Any handler chains configured using the Spring configuration override the handler chains configured programmaticaly. |
Adding a handler chain to a consumer involves explicitly building the chain of handlers. Then you set the
handler chain directly on the service proxy's Binding object.
To add a handler chain to a consumer you do the following:
Create a List<Handler> object to hold the handler chain.
Create an instance of each handler that will be added to the chain.
Add each of the instantiated handler objects to the list in the order they are to be invoked by the runtime.
Get the Binding object from the service proxy.
![]() | Tip |
|---|---|
Fuse Services Framework provides an implementation of the |
Set the handler chain on the proxy using the Binding object's
setHandlerChain() method.
Example 21.14 shows code for adding a handler chain to a consumer.
Example 21.14. Adding a Handler Chain to a Consumer
import javax.xml.ws.BindingProvider; import javax.xml.ws.handler.Handler; import java.util.ArrayList; import java.util.List; import org.apache.cxf.jaxws.binding.DefaultBindingImpl; ... SmallNumberHandler sh = new SmallNumberHandler();List<Handler> handlerChain = new ArrayList<Handler>();
handlerChain.add(sh);
DefaultBindingImpl binding = ((BindingProvider)proxy).getBinding();
binding.getBinding().setHandlerChain(handlerChain);
The code in Example 21.14 does the following:
You add a handler chain to a service provider by decorating either the SEI or the implementation class with
the @HandlerChain annotation. The annotation points to a meta-data file defining the
handler chain used by the service provider.
To add handler chain to a service provider you do the following:
Decorate the provider's implementation class with the @HandlerChain
annotation.
Create a handler configuration file that defines the handler chain.
The javax.jws.HandlerChain annotation decorates service provider's implementation
class. It instructs the runtime to load the handler chain configuration file specified by its file
property.
The annotation's file property supports two methods for identifying the handler configuration file to load:
a URL
a relative path name
Example 21.15 shows a service provider implementation that will
use the handler chain defined in a file called handlers.xml. handlers.xml
must be located in the directory from which the service provider is run.
Example 21.15. Service Implementation that Loads a Handler Chain
import javax.jws.HandlerChain; import javax.jws.WebService; ... @WebService(name = "AddNumbers", targetNamespace = "http://apache.org/handlers", portName = "AddNumbersPort", endpointInterface = "org.apache.handlers.AddNumbers", serviceName = "AddNumbersService") @HandlerChain(file = "handlers.xml") public class AddNumbersImpl implements AddNumbers { ... }
The handler configuration file defines a handler chain using the XML grammar that accompanies JSR 109(Web Services for Java
EE, Version 1.2). This grammar is defined in the http://java.sun.com/xml/ns/javaee.
The root element of the handler configuration file is the handler-chains element. The
handler-chains element has one or more handler-chain elements.
The handler-chain element define a handler chain. Table 21.1
describes the handler-chain element's children.
Table 21.1. Elements Used to Define a Server-Side Handler Chain
| Element | Description |
|---|---|
handler
| Contains the elements that describe a handler. |
service-name-pattern
| Specifies the QName of the WSDL service element defining the service to
which the handler chain is bound. You can use * as a wildcard when defining the QName. |
port-name-pattern
| Specifies the QName of the WSDL port element defining the endpoint to
which the handler chain is bound. You can use * as a wildcard when defining the QName. |
protocol-binding
|
Specifies the message binding for which the handler chain is used. The binding is specified as a URI or using one
of the following aliases: For more information about message binding URIs see Appendix A in Configuring Web Service Endpoints. |
The handler-chain element is only required to have a single handler
element as a child. It can, however, support as many handler elements as needed to define
the complete handler chain. The handlers in the chain are executed in the order they specified in the handler chain definition.
![]() | Important |
|---|---|
The final order of execution will be determined by sorting the specified handlers into logical handlers and protocol handlers. Within the groupings, the order specified in the configuration will be used. |
The other children, such as protocol-binding, are used to limit the scope of the defined handler chain.
For example, if you use the service-name-pattern element, the handler chain will only be attached to
service providers whose WSDL port element is a child of the specified WSDL
service element. You can only use one of these limiting children in a
handler element.
The handler element defines an individual handler in a handler chain. Its
handler-class child element specifies the fully qualified name of the class implementing the
handler. The handler element can also have an optional
handler-name element that specifies a unique name for the handler.
Example 21.16 shows a handler configuration file that defines a single handler chain. The chain is made up of two handlers.
Example 21.16. Handler Configuration File
<handler-chains xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee"> <handler-chain> <handler> <handler-name>LoggingHandler</handler-name> <handler-class>demo.handlers.common.LoggingHandler</handler-class> </handler> <handler> <handler-name>AddHeaderHandler</handler-name> <handler-class>demo.handlers.common.AddHeaderHandler</handler-class> </handler> </handler-chain> </handler-chains>
The easiest way to configure an endpoint to use a handler chain is to define the chain in the endpoint's configuration. This is
done by adding a jaxwxs:handlers child to the element configuring the endpoint.
![]() | Important |
|---|---|
A handler chain added through the configuration file takes precedence over a handler chain configured programatically. |
To configure an endpoint to load a handler chain you do the following:
If the endpoint does not already have a configuration element, add one.
For more information on configuring Fuse Services Framework endpoints see Configuring JAX-WS Endpoints in Configuring Web Service Endpoints.
Add a jaxws:handlers child element to the endpoint's configuration element.
For each handler in the chain, add a bean element specifying the class that implements the handler.
![]() | Tip |
|---|---|
If your handler implementation is used in more than one place you can reference a |
The jaxws:handlers element defines a handler chain in an endpoint's configuration. It can appear as a child to all of the JAX-WS
endpoint configuration elements. These are:
jaxws:endpoint configures a service provider.
jaxws:server also configures a service provider.
jaxws:client configures a service consumer.
You add handlers to the handler chain in one of two ways:
add a bean element defining the implementation class
use a ref element to refer to a named bean element from elsewhere in the configuration
file
The order in which the handlers are defined in the configuration is the order in which they will be executed. The order may be modified if you mix logical handlers and protocol handlers. The run time will sort them into the proper order while maintaining the basic order specified in the configuration.
Example 21.17 shows the configuration for a service provider that loads a handler chain.
Example 21.17. Configuring an Endpoint to Use a Handler Chain In Spring
<beans ... xmlns:jaxws="http://cxf.apache.org/jaxws" ... schemaLocation="... http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd ..."> <jaxws:endpoint id="HandlerExample" implementor="org.apache.cxf.example.DemoImpl" address="http://localhost:8080/demo"> <jaxws:handlers> <bean class="demo.handlers.common.LoggingHandler" /> <bean class="demo.handlers.common.AddHeaderHandler" /> </jaxws:handlers> </jaws:endpoint> </beans>
Plug-in Setup — before you can use the Fuse Services Framework plug-ins, you must first add the proper dependencies and repositories to your POM.
You need to add the following dependencies to your project's POM:
the JAX-WS frontend
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>version</version>
</dependency>the HTTP transport
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>version</version>
</dependency>the Jetty transport
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http-jetty</artifactId>
<version>version</version>
</dependency>To ensure that you are using the Progress versions of the plug-ins you need to add the Fuse Services Framework repositories to the project's POM:
the plug-in repository
<pluginRepository>
<id>fusesource.m2</id>
<name>Fuse Services Framework Open Source Community Release Repository</name>
<url>http://repo.fusesource.com/maven2</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
<releases>
<enabled>true</enabled>
</releases>
</pluginRepository>the Fuse Services Framework release repository
<repository>
<id>fusesource.m2</id>
<name>Fuse Services Framework Open Source Community Release Repository</name>
<url>http://repo.fusesource.com/maven2</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
<releases>
<enabled>true</enabled>
</releases>
</repository>the Fuse Services Framework snapshot repository
<repository>
<id>fusesource.m2-snapshot</id>
<name>Fuse Services Framework Open Source Community Snapshot Repository</name>
<url>http://repo.fusesource.com/maven2-snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</repository>cxf-codegen-plugin — generates JAX-WS compliant Java code from a WSDL document
<plugin> <groupId>org.apache.cxf</groupId> <artifactId>cxf-codegen-plugin</artifactId> <version>version</version> <executions> <execution> <id>generate-sources</id> <configuration> <defaultOptions><option>...</option>... </defaultOptions> <wsdlOptions> <wsdlOption> <wsdl>wsdlPath</wsdl><option>...</option>... </wsdlOption> ... </wsdlOptions> </configuration> <goals> <goal>wsdl2java</goal> </goals> </execution> </executions> </plugin>
The wsdl2java task takes a WSDL document and generates fully annotated Java code from which to implement a
service. The WSDL document must have a valid portType element, but it does not need to contain a
binding element or a service element. Using the optional arguments you can
customize the generated code.
At least one wsdlOptions element is required to configure the plug-in. The
wsdlOptions element's wsdl child is required and specifies a WSDL document
to be processed by the plug-in. In addition to the wsdl element, the
wsdlOptions element can take a number of children that can customize how the WSDL document is
processed.
![]() | Tip |
|---|---|
More than one |
The defaultOptions element is an optional element. It can be used to set options that are used
across all of the specified WSDL documents.
![]() | Important |
|---|---|
If an option is duplicated in the |
The options used to manage the code generation process are reviewed in the following table.
| Option | Interpretation |
|---|---|
-? | Displays the online help for this utility. |
-help | |
-h | |
-fe | Specifies the front end used by the code generator. The default is jaxws.[a] |
-db | Specifies the data binding used by the code generator. The default is jaxb.[b] |
-wv | Specifies the WSDL version expected by the tool. The default is 1.1.[c] |
-p [wsdlNamespace=]PackageName | Specifies zero, or more, package names to use for the generated code. Optionally specifies the WSDL namespace to package name mapping. |
-b | Specifies zero, or more, JAXWS or JAXB binding files. Use spaces to separate multiple entries. |
-sn | Specifies the name of the WSDL service for which code is to be generated. The default is to generate code for every service in the WSDL document. |
-d | Specifies the directory into which the generated code files are written. |
-catalog | Specifies the URL of an XML catalog to use for resolving imported schemas and WSDL documents. |
-compile | Compiles generated Java files. |
-classdir | Specifies the directory into which the compiled class files are written. |
-client | Generates starting point code for a client mainline. |
-server | Generates starting point code for a server mainline. |
-impl | Generates starting point code for an implementation object. |
-all | Generates all starting point code: types, service proxy, service interface, server mainline, client mainline, implementation object, and an Ant build.xml file. |
-ant | Generates the Ant build.xml file. |
-keep | Instructs the tool to not overwrite any existing files. |
-defaultValues[=DefaultValueProvider] | Instructs the tool to generate default values for the generated client and the generated implementation. Optionally, you can also supply the name of the class used to generate the default values. By default, the RandomValueProvider class is used. |
-nexclude schema-namespace[=java-packagename] | Ignore the specified WSDL schema namespace when generating code. This option may be specified multiple times. Also, optionally specifies the Java package name used by types described in the excluded namespace(s). |
-exsh (true/false) | Enables or disables processing of extended soap header message binding. Default is false. |
-dns (true/false) | Enables or disables the loading of the default namespace package name mapping. Default is true. |
-dex (true/false) | Enables or disables the loading of the default excludes namespace mapping. Default is true. |
-wsdlLocation | Specifies the value of the @WebService annotation's wsdlLocation property. |
-xjc | Specifies a comma separated list of arguments to be passed to directly to the XJC when the JAXB data binding is being used. To get a list of all possible XJC arguments use the -xjc-X. |
-noAddressBinding | Instructs the tool to use the Fuse Services Framework proprietary WS-Addressing type instead of the JAX-WS 2.1 compliant mapping. |
-validate | Instructs the tool to validate the WSDL document before attempting to generate any code. |
-v | Displays the version number for the tool. |
-verbose | Displays comments during the code generation process. |
-quiet | Suppresses comments during the code generation process. |
wsdlfile | The path and name of the WSDL file to use in generating the code. |
[a] Currently, Fuse Services Framework only provides the JAX-WS front end for the code generator. [b] Currently, Fuse Services Framework only provides the JAXB data binding for the code generator. [c] Currently, Fuse Services Framework only provides WSDL 1.1 support for the code generator. | |
java2ws — generates a WSDL document from Java code
<plugin> <groupId>org.apache.cxf</groupId> <artifactId>cxf-java2ws-plugin</artifactId> <version>version</version> <executions> <execution> <id>process-classes</id> <phase>process-classes</phase> <configuration> <className>className</className><option>...</option>... </configuration> <goals> <goal>java2ws</goal> </goals> </execution> </executions> </plugin>
The java2ws task takes a service endpoint implementation (SEI) and generates the support files used to implement a Web service. It can generate the following:
a WSDL document
the server code needed to deploy the service as a POJO
client code for accessing the service
wrapper and fault beans
The plug-in requires that the className configuration element is present. The element's value is the
fully qualified name of the SEI to be processed.
The configuration element's listed in the following table can be used to fine tune the WSDL generation.
| Element | Description |
|---|---|
frontend | Specifies front end to use for processing the SEI and generating the support classes.
jaxws is the default. simple is also supported. |
databinding | Specifies the data binding used for processing the SEI and generating the support classes. The default when using the
JAX-WS front end is jaxb. The default when using the simple frontend is aegis. |
genWsdl | Instructs the tool to generate a WSDL document when set to true. |
genWrapperbean | Instructs the tool to generate the wrapper bean and the fault beans when set to true. |
genClient | Instructs the tool to generate client code when set to true. |
genServer | Instructs the tool to generate server code when set to true. |
outputFile | Specifies the name of the generated WSDL file. |
classpath | Specifies the classpath searched when processing the SEI. |
soap12 | Specifies that the generated WSDL document is to include a SOAP 1.2 binding when set to
true. |
targetNamespace | Specifies the target namespace to use in the generated WSDL file. |
serviceName | Specifies the value of the generated service element's
name attribute. |