User Guide
From JBossws
Web Service Concepts
Document/Literal
With document style web services two business partners agree on the exchange of complex business documents that are well defined in XML schema. For example, one party sends a document describing a purchase order, the other responds (immediately or later) with a document that describes the status of the purchase order. No need to agree on such low level details as operation names and their associated parameters.
The payload of the SOAP message is an XML document that can be validated against XML schema.
Document is defined by the style attribute on the SOAP binding.
<binding name='EndpointInterfaceBinding' type='tns:EndpointInterface'>
<soap:binding style='document' transport='http://schemas.xmlsoap.org/soap/http'/>
<operation name='concat'>
<soap:operation soapAction=''/>
<input>
<soap:body use='literal'/>
</input>
<output>
<soap:body use='literal'/>
</output>
</operation>
</binding>
With document style web services the payload of every message is defined by a complex type in XML schema.
<complexType name='concatType'>
<sequence>
<element name='String_1' nillable='true' type='string'/>
<element name='long_1' type='long'/>
</sequence>
</complexType>
<element name='concat' type='tns:concatType'/>
Therefore, message parts must refer to an element from the schema.
<message name='EndpointInterface_concat'> <part name='parameters' element='tns:concat'/> </message>
The following message definition is invalid.
<message name='EndpointInterface_concat'> <part name='parameters' type='tns:concatType'/> </message>
Document/Literal (Bare)
Bare is an implementation detail from the Java domain. Neither in the abstract contract (i.e. wsdl+schema) nor at the SOAP message level is a bare endpoint recognizable.
A bare endpoint or client uses a Java bean that represents the entire document payload.
@WebService
@SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
public class DocBareServiceImpl
{
@WebMethod
public SubmitBareResponse submitPO(SubmitBareRequest poRequest)
{
...
}
}
The trick is that the Java beans representing the payload contain JAXB annotations that define how the payload is represented on the wire.
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "SubmitBareRequest", namespace="http://soapbinding.samples.jaxws.ws.test.jboss.org/", propOrder = { "product" })
@XmlRootElement(namespace="http://soapbinding.samples.jaxws.ws.test.jboss.org/", name = "SubmitPO")
public class SubmitBareRequest
{
@XmlElement(namespace="http://soapbinding.samples.jaxws.ws.test.jboss.org/", required = true)
private String product;
...
}
Document/Literal (Wrapped)
Wrapped is an implementation detail from the Java domain. Neither in the abstract contract (i.e. wsdl+schema) nor at the SOAP message level is a wrapped endpoint recognizable.
A wrapped endpoint or client uses the individual document payload properties. Wrapped is the default and does not have to be declared explicitly.
@WebService
public class DocWrappedServiceImpl
{
@WebMethod
@RequestWrapper (className="org.somepackage.SubmitPO")
@ResponseWrapper (className="org.somepackage.SubmitPOResponse")
public String submitPO(String product, int quantity)
{
...
}
}
Note, that with JBossWS the request/response wrapper annotations are not required, they will be generated on demand using sensible defaults.
RPC/Literal
With RPC there is a wrapper element that names the endpoint operation. Child elements of the RPC parent are the individual parameters.
The SOAP body is constructed based on some simple rules:
- The port type operation name defines the endpoint method name
- Message parts are endpoint method parameters
RPC is defined by the style attribute on the SOAP binding.
<binding name='EndpointInterfaceBinding' type='tns:EndpointInterface'>
<soap:binding style='rpc' transport='http://schemas.xmlsoap.org/soap/http'/>
<operation name='echo'>
<soap:operation soapAction=''/>
<input>
<soap:body namespace='http://org.jboss.ws/samples/jsr181pojo' use='literal'/>
</input>
<output>
<soap:body namespace='http://org.jboss.ws/samples/jsr181pojo' use='literal'/>
</output>
</operation>
</binding>
With rpc style web services the portType names the operation (i.e. the java method on the endpoint)
<portType name='EndpointInterface'> <operation name='echo' parameterOrder='String_1'> <input message='tns:EndpointInterface_echo'/> <output message='tns:EndpointInterface_echoResponse'/> </operation> </portType>
Operation parameters are defined by individual message parts.
<message name='EndpointInterface_echo'> <part name='String_1' type='xsd:string'/> </message> <message name='EndpointInterface_echoResponse'> <part name='result' type='xsd:string'/> </message>
Note, there is no complex type in XML schema that could validate the entire SOAP message payload.
@WebService
@SOAPBinding(style = SOAPBinding.Style.RPC)
public class JSEBean01
{
@WebMethod
@WebResult(name="result")
public String echo(@WebParam(name="String_1") String input)
{
...
}
}
The element names of RPC parameters/return values may be defined using the JAX-WS WebParam and WebResult annotations respectively.
RPC/Encoded
SOAP encodeding style is defined by the infamous chapter 5 of the SOAP-1.1 specification. It has inherent interoperability issues that cannot be fixed. The Basic Profile-1.0 prohibits this encoding style in 4.1.7 SOAP encodingStyle Attribute.
JBossWS has basic support for rpc/encoded that is provided as is for simple interop scenarios with SOAP stacks that do not support literal encoding.
Specifically, JBossWS does not support
- element references
- soap arrays as bean properties
Web Service Endpoints
JAX-WS simplifies the development model for a web service endpoint a great deal. In short, an endpoint implementation bean is annotated with JAX-WS annotations and deployed to the server. The server automatically generates and publishes the abstract contract (i.e. wsdl+schema) for client consumption. All marshalling/unmarshalling is delegated to JAXB [2].
Plain old Java Object (POJO)
Let's take a look at simple POJO endpoint implementation. All endpoint associated metadata is provided via JSR-181 annotations
@WebService
@SOAPBinding(style = SOAPBinding.Style.RPC)
public class JSEBean01
{
@WebMethod
public String echo(String input)
{
...
}
}
The endpoint as a web application
A JAX-WS java service endpoint (JSE) is deployed as a web application.
<web-app ...>
<servlet>
<servlet-name>TestService</servlet-name>
<servlet-class>org.jboss.test.ws.jaxws.samples.jsr181pojo.JSEBean01</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>TestService</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
Packaging the endpoint
A JSR-181 java service endpoint (JSE) is packaged as a web application in a *.war file.
<war warfile="${build.dir}/libs/jbossws-samples-jsr181pojo.war" webxml="${build.resources.dir}/samples/jsr181pojo/WEB-INF/web.xml">
<classes dir="${build.dir}/classes">
<include name="org/jboss/test/ws/samples/jsr181pojo/JSEBean01.class"/>
</classes>
</war>
Note, only the endpoint implementation bean and web.xml are required.
Accessing the generated WSDL
A successfully deployed service endpoint will show up in the service endpoint manager. This is also where you find the links to the generated wsdl.
http://yourhost:8080/jbossws/services
Note, it is also possible to generate the abstract contract off line using jbossw tools. For details of that please see Bottom-Up (Java to WSDL)
EJB3 Stateless Session Bean (SLSB)
The JAX-WS programming model support the same set of annotations on EJB3 stateless session beans as on Plain old Java Object (POJO) endpoints. EJB-2.1 endpoints are supported using the JAX-RPC progamming model.
@Stateless
@Remote(EJB3RemoteInterface.class)
@RemoteBinding(jndiBinding = "/ejb3/EJB3EndpointInterface")
@WebService
@SOAPBinding(style = SOAPBinding.Style.RPC)
public class EJB3Bean01 implements EJB3RemoteInterface
{
@WebMethod
public String echo(String input)
{
...
}
}
Above you see an EJB-3.0 stateless session bean that exposes one method both on the remote interface and on and as an endpoint operation.
Packaging the endpoint
A JSR-181 EJB service endpoint is packaged as an ordinary ejb deployment.
<jar jarfile="${build.dir}/libs/jbossws-samples-jsr181ejb.jar">
<fileset dir="${build.dir}/classes">
<include name="org/jboss/test/ws/samples/jsr181ejb/EJB3Bean01.class"/>
<include name="org/jboss/test/ws/samples/jsr181ejb/EJB3RemoteInterface.class"/>
</fileset>
</jar>
Accessing the generated WSDL
A successfully deployed service endpoint will show up in the service endpoint manager. This is also where you find the links to the generated wsdl.
http://yourhost:8080/jbossws/services
Note, it is also possible to generate the abstract contract off line using jbossw tools. For details of that please see Bottom-Up (Java to WSDL)
Endpoint Provider
JAX-WS services typically implement a native Java service endpoint interface (SEI), perhaps mapped from a WSDL port type, either directly or via the use of annotations.
Java SEIs provide a high level Java-centric abstraction that hides the details of converting between Java objects and their XML representations for use in XML-based messages. However, in some cases it is desirable for services to be able to operate at the XML message level. The Provider interface offers an alternative to SEIs and may be implemented by services wishing to work at the XML message level.
A Provider based service instance’s invoke method is called for each message received for the service.
@WebServiceProvider(wsdlLocation = "WEB-INF/wsdl/Provider.wsdl")
@ServiceMode(value = Service.Mode.PAYLOAD)
public class ProviderBeanPayload implements Provider<Source>
{
public Source invoke(Source req)
{
// Access the entire request PAYLOAD and return the response PAYLOAD
}
}
Note, Service.Mode.PAYLOAD is the default and does not have to be declared explicitly. You can also use Service.Mode.MESSAGE to access the entire SOAP message (i.e. with MESSAGE the Provider can also see SOAP Headers)
The abstract contract for a provider endpoint cannot be derived/generated automatically. Therefore it is necessary to specify the wsdlLocation with the @WebServiceProvider annotation.
WebServiceContext
The WebServiceContext is treated as an injectable resource that can be set at the time an endpoint is initialized. The WebServiceContext object will then use thread-local information to return the correct information regardless of how many threads are concurrently being used to serve requests addressed to the same endpoint object.
@WebService
public class EndpointJSE
{
@Resource
WebServiceContext wsCtx;
@WebMethod
public String testGetMessageContext()
{
SOAPMessageContext jaxwsContext = (SOAPMessageContext)wsCtx.getMessageContext();
return jaxwsContext != null ? "pass" : "fail";
}
@WebMethod
public String testGetUserPrincipal()
{
Principal principal = wsCtx.getUserPrincipal();
return principal.getName();
}
@WebMethod
public boolean testIsUserInRole(String role)
{
return wsCtx.isUserInRole(role);
}
}
Secure endpoints
Securing an endpoint requires you to set the authentication configuration.
Then you might want to secure the communication between service provider and consumer. This can be done at different levels:
Web Service Clients
Service
Service is an abstraction that represents a WSDL service. A WSDL service is a collection of related ports, each of which consists of a port type bound to a particular protocol and available at a particular endpoint address.
For most clients, you will start with a set of stubs generated from the WSDL. One of these will be the service, and you will create objects of that class in order to work with the service (see "static case" below).
Service Usage
Static case
Most clients will start with a WSDL file, and generate some stubs using jbossws tools like wsconsume. This usually gives a mass of files, one of which is the top of the tree. This is the service implementation class.
The generated implementation class can be recognised as it will have two public constructors, one with no arguments and one with two arguments, representing the wsdl location (a java.net.URL) and the service name (a javax.xml.namespace.QName) respectively.
Usually you will use the no-argument constructor. In this case the WSDL location and service name are those found in the WSDL. These are set implicitly from the WebServiceClient annotation that decorates the generated class.
The following code snippet shows the generated constructors from the generated class:
// Generated Service Class
@WebServiceClient(name="StockQuoteService", targetNamespace="http://example.com/stocks", wsdlLocation="http://example.com/stocks.wsdl")
public class StockQuoteService extends javax.xml.ws.Service
{
public StockQuoteService()
{
super(new URL("http://example.com/stocks.wsdl"), new QName("http://example.com/stocks", "StockQuoteService"));
}
public StockQuoteService(String wsdlLocation, QName serviceName)
{
super(wsdlLocation, serviceName);
}
...
}
Section Dynamic Proxy explains how to obtain a port from the service and how to invoke an operation on the port. If you need to work with the XML payload directly or with the XML representation of the entire SOAP message, have a look at Dispatch.
Dynamic case
In the dynamic case, when nothing is generated, a web service client uses Service.create to create Service instances, the following code illustrates this process.
URL wsdlLocation = new URL("http://example.org/my.wsdl");
QName serviceName = new QName("http://example.org/sample", "MyService");
Service service = Service.create(wsdlLocation, serviceName);
This is the nastiest way to work with JBossWs. Older versions have extensive details on DII as it was then known.
Handler Resolver
JAX-WS provides a flexible plug-in framework for message processing modules, known as handlers, that may be used to extend the capabilities of a JAX-WS runtime system. Handler Framework describes the handler framework in detail. A Service instance provides access to a HandlerResolver via a pair of getHandlerResolver/setHandlerResolver methods that may be used to configure a set of handlers on a per-service, per-port or per-protocol binding basis.
When a Service instance is used to create a proxy or a Dispatch instance then the handler resolver currently registered with the service is used to create the required handler chain. Subsequent changes to the handler resolver configured for a Service instance do not affect the handlers on previously created proxies, or Dispatch instances.
[TODO] (JBWS-1512) Provide a sample for Service HandlerResolver
Executor
Service instances can be configured with a java.util.concurrent.Executor. The executor will then be used to invoke any asynchronous callbacks requested by the application. The setExecutor and getExecutor methods of Service can be used to modify and retrieve the executor configured for a service.
[TODO] (JBWS-1513) Provide a sample for Service Executor
Dynamic Proxy
You can create an instance of a client proxy using one of getPort methods on the Service.
/**
* The getPort method returns a proxy. A service client
* uses this proxy to invoke operations on the target
* service endpoint. The <code>serviceEndpointInterface</code>
* specifies the service endpoint interface that is supported by
* the created dynamic proxy instance.
**/
public <T> T getPort(QName portName, Class<T> serviceEndpointInterface)
{
...
}
/**
* The getPort method returns a proxy. The parameter
* <code>serviceEndpointInterface</code> specifies the service
* endpoint interface that is supported by the returned proxy.
* In the implementation of this method, the JAX-WS
* runtime system takes the responsibility of selecting a protocol
* binding (and a port) and configuring the proxy accordingly.
* The returned proxy should not be reconfigured by the client.
*
**/
public <T> T getPort(Class<T> serviceEndpointInterface)
{
...
}
The service endpoint interface (SEI) is usually generated using tools. For details see Top Down (WSDL to Java)
A generated static Service usually also offers typed methods to get ports. These methods also return dynamic proxies that implement the SEI.
@WebServiceClient(name = "TestEndpointService", targetNamespace = "http://org.jboss.ws/wsref",
wsdlLocation = "http://localhost.localdomain:8080/jaxws-samples-webserviceref?wsdl")
public class TestEndpointService extends Service
{
...
public TestEndpointService(URL wsdlLocation, QName serviceName) {
super(wsdlLocation, serviceName);
}
@WebEndpoint(name = "TestEndpointPort")
public TestEndpoint getTestEndpointPort()
{
return (TestEndpoint)super.getPort(TESTENDPOINTPORT, TestEndpoint.class);
}
}
WebServiceRef
The WebServiceRef annotation is used to declare a reference to a Web service. It follows the resource pattern exemplified by the javax.annotation.Resource annotation in JSR-250 [5]
There are two uses to the WebServiceRef annotation:
- To define a reference whose type is a generated service class. In this case, the type and value element will both refer to the generated service class type. Moreover, if the reference type can be inferred by the field/method declaration the annotation is applied to, the type and value elements MAY have the default value (Object.class, that is). If the type cannot be inferred, then at least the type element MUST be present with a non-default value.
- To define a reference whose type is a SEI. In this case, the type element MAY be present with its default value if the type of the reference can be inferred from the annotated field/method declaration, but the value element MUST always be present and refer to a generated service class type (a subtype of javax.xml.ws.Service). The wsdlLocation element, if present, overrides theWSDL location information specified in the WebService annotation of the referenced generated service class.
public class EJB3Client implements EJB3Remote
{
@WebServiceRef
public TestEndpointService service4;
@WebServiceRef
public TestEndpoint port3;
WebServiceRef Customization
In jboss-5.0.x we offer a number of overrides and extensions to the WebServiceRef annotation. These include
- define the port that should be used to resolve a container-managed port
- define default Stub property settings for Stub objects
- define the URL of a final WSDL document to be used
Example:
<service-ref>
<service-ref-name>OrganizationService</service-ref-name>
<wsdl-override>file:/wsdlRepository/organization-service.wsdl</wsdl-override>
</service-ref>
<service-ref>
<service-ref-name>OrganizationService</service-ref-name>
<config-name>Secure Client Config</config-name>
<config-file>META-INF/jbossws-client-config.xml</config-file>
<handler-chain>META-INF/jbossws-client-handlers.xml</handler-chain>
</service-ref>
<service-ref>
<service-ref-name>SecureService</service-ref-name>
<service-class-name>org.jboss.tests.ws.jaxws.webserviceref.SecureEndpointService</service-class-name>
<service-qname>{http://org.jboss.ws/wsref}SecureEndpointService</service-qname>
<port-info>
<service-endpoint-interface>org.jboss.tests.ws.jaxws.webserviceref.SecureEndpoint</service-endpoint-interface>
<port-qname>{http://org.jboss.ws/wsref}SecureEndpointPort</port-qname>
<stub-property>
<name>javax.xml.ws.security.auth.username</name>
<value>kermit</value>
</stub-property>
<stub-property>
<name>javax.xml.ws.security.auth.password</name>
<value>thefrog</value>
</stub-property>
</port-info>
</service-ref>
For details please see service-ref_5_0.dtd in the jboss docs directory.
Dispatch
XMLWeb Services use XML messages for communication between services and service clients. The higher level JAX-WS APIs are designed to hide the details of converting between Java method invocations and the corresponding XML messages, but in some cases operating at the XML message level is desirable. The Dispatch interface provides support for this mode of interaction.
Dispatch supports two usage modes, identified by the constants javax.xml.ws.Service.Mode.MESSAGE and javax.xml.ws.Service.Mode.PAYLOAD respectively:
Message In this mode, client applications work directly with protocol-specific message structures. E.g., when used with a SOAP protocol binding, a client application would work directly with a SOAP message.
Message Payload In this mode, client applications work with the payload of messages rather than the messages themselves. E.g., when used with a SOAP protocol binding, a client application would work with the contents of the SOAP Body rather than the SOAP message as a whole.
Dispatch is a low level API that requires clients to construct messages or message payloads as XML and requires an intimate knowledge of the desired message or payload structure. Dispatch is a generic class that supports input and output of messages or message payloads of any type.
Service service = Service.create(wsdlURL, serviceName);
Dispatch dispatch = service.createDispatch(portName, StreamSource.class, Mode.PAYLOAD);
String payload = "<ns1:ping xmlns:ns1='http://oneway.samples.jaxws.ws.test.jboss.org/'/>";
dispatch.invokeOneWay(new StreamSource(new StringReader(payload)));
payload = "<ns1:feedback xmlns:ns1='http://oneway.samples.jaxws.ws.test.jboss.org/'/>";
Source retObj = (Source)dispatch.invoke(new StreamSource(new StringReader(payload)));
Asynchronous Invocations
The BindingProvider interface represents a component that provides a protocol binding for use by clients, it is implemented by proxies and is extended by the Dispatch interface.
BindingProvider instances may provide asynchronous operation capabilities. When used, asynchronous operation invocations are decoupled from the BindingProvider instance at invocation time such that the response context is not updated when the operation completes. Instead a separate response context is made available using the Response interface.
public void testInvokeAsync() throws Exception
{
URL wsdlURL = new URL("http://" + getServerHost() + ":8080/jaxws-samples-asynchronous?wsdl");
QName serviceName = new QName(targetNS, "TestEndpointService");
Service service = Service.create(wsdlURL, serviceName);
TestEndpoint port = service.getPort(TestEndpoint.class);
Response response = port.echoAsync("Async");
// access future
String retStr = (String) response.get();
assertEquals("Async", retStr);
}
Oneway Invocations
@Oneway indicates that the given web method has only an input message and no output. Typically, a oneway method returns the thread of control to the calling application prior to executing the actual business method.
@WebService (name="PingEndpoint")
@SOAPBinding(style = SOAPBinding.Style.RPC)
public class PingEndpointImpl
{
private static String feedback;
@WebMethod
@Oneway
public void ping()
{
log.info("ping");
feedback = "ok";
}
@WebMethod
public String feedback()
{
log.info("feedback");
return feedback;
}
}
JMS Transport Clients
Since jbossws-2.0.3 we support JAX-WS clients that use JMS transport.
JMS transport is activated on the client side when the endpoint location uses the 'jms' URL schema
<binding name='JMSBinding' type='tns:OrganizationJMSEndpoint'>
<soap:binding style='rpc' transport='http://www.example.org/2006/06/soap/bindings/JMS/'/>
<operation name='getContactInfo'>
<soap:operation soapAction=''/>
<input>
<soap:body namespace='http://org.jboss.ws/samples/jmstransport' use='literal'/>
</input>
<output>
<soap:body namespace='http://org.jboss.ws/samples/jmstransport' use='literal'/>
</output>
</operation>
</binding>
<service name='OrganizationJMSEndpointService'>
<port binding='tns:JMSBinding' name='JMSEndpointPort'>
<soap:address location='jms://queue/RequestQueue?replyToName=queue/ResponseQueue'/>
</port>
</service>
The service that implements the JMS remote connection is loaded using the key
org.jboss.ws.core.client.RemoteConnection.jms
Like any other service, this can be overwritten using a system property.
The JAX-WS client code is essentially no different from a client using HTTP as transport
public void testJMSEndpointPort() throws Exception
{
URL wsdlURL = new File("resources/jaxws/samples/jmstransport/jmsservice.wsdl").toURL();
QName serviceName = new QName("http://org.jboss.ws/samples/jmstransport", "OrganizationJMSEndpointService");
QName portName = new QName("http://org.jboss.ws/samples/jmstransport", "JMSEndpointPort");
Service service = Service.create(wsdlURL, serviceName);
Organization port = service.getPort(portName, Organization.class);
String res = port.getContactInfo("mafia");
assertEquals("The 'mafia' boss is currently out of office, please call again.", res);
}
Common API
This sections describes concepts that apply equally to Web Service Endpoints and Web Service Clients
Handler Framework
The handler framework is implemented by a JAX-WS protocol binding in both client and server side runtimes. Proxies, and Dispatch instances, known collectively as binding providers, each use protocol bindings to bind their abstract functionality to specific protocols.
Client and server-side handlers are organized into an ordered list known as a handler chain. The handlers within a handler chain are invoked each time a message is sent or received. Inbound messages are processed by handlers prior to binding provider processing. Outbound messages are processed by handlers after any binding provider processing.
Handlers are invoked with a message context that provides methods to access and modify inbound and outbound messages and to manage a set of properties. Message context properties may be used to facilitate communication between individual handlers and between handlers and client and service implementations. Different types of handlers are invoked with different types of message context.
Logical Handler
Handlers that only operate on message context properties and message payloads. Logical handlers are protocol agnostic and are unable to affect protocol specific parts of a message. Logical handlers are handlers that implement javax.xml.ws.handler.LogicalHandler.
Protocol Handler
Handlers that operate on message context properties and protocol specific messages. Protocol handlers are specific to a particular protocol and may access and change protocol specific aspects of a message. Protocol handlers are handlers that implement any interface derived from javax.xml.ws.handler.Handler except javax.xml.ws.handler.LogicalHandler.
Service endpoint handlers
On the service endpoint, handlers are defined using the @HandlerChain annotation.
@WebService
@HandlerChain(file = "jaxws-server-source-handlers.xml")
public class SOAPEndpointSourceImpl
{
...
}
The location of the handler chain file supports 2 formats
1. An absolute java.net.URL in externalForm. (ex: http://myhandlers.foo.com/handlerfile1.xml)
2. A relative path from the source file or class file. (ex: bar/handlerfile1.xml)
Service client handlers
On the client side, handler can be configured using the @HandlerChain annotation on the SEI or dynamically using the API.
Service service = Service.create(wsdlURL, serviceName);
Endpoint port = (Endpoint)service.getPort(Endpoint.class);
BindingProvider bindingProvider = (BindingProvider)port;
List<Handler> handlerChain = new ArrayList<Handler>();
handlerChain.add(new LogHandler());
handlerChain.add(new AuthorizationHandler());
handlerChain.add(new RoutingHandler());
bindingProvider.getBinding().setHandlerChain(handlerChain); // important!
Message Context
MessageContext is the super interface for all JAX-WS message contexts. It extends Map<String,Object> with additional methods and constants to manage a set of properties that enable handlers in a handler chain to share processing related state. For example, a handler may use the put method to insert a property in the message context that one or more other handlers in the handler chain may subsequently obtain via the get method.
Properties are scoped as either APPLICATION or HANDLER. All properties are available to all handlers for an instance of an MEP on a particular endpoint. E.g., if a logical handler puts a property in the message context, that property will also be available to any protocol handlers in the chain during the execution of an MEP instance. APPLICATION scoped properties are also made available to client applications (see section 4.2.1) and service endpoint implementations. The defaultscope for a property is HANDLER.
Accessing the message context
There is currently no portable way of doing this in 4.0.5. @WebServiceContext injection will be available with 4.2. In the meantime you can access the message context like this:
CommonMessageContext msgContext = MessageContextAssociation.peekMessageContext(); msgContext.setProperty(<Name>, <Value>);
Logical Message Context
Logical handlers are passed a message context of type LogicalMessageContext when invoked. LogicalMessageContext extends MessageContext with methods to obtain and modify the message payload, it does not provide access to the protocol specific aspects of amessage. A protocol binding defines what component of a message are available via a logical message context. The SOAP binding defines that a logical handler deployed in a SOAP binding can access the contents of the SOAP body but not the SOAP headers whereas the XML/HTTP binding defines that a logical handler can access the entire XML payload of a message.
SOAP Message Context
SOAP handlers are passed a SOAPMessageContext when invoked. SOAPMessageContext extends MessageContext with methods to obtain and modify the SOAP message payload.
Fault Handling
An implementation may thow a SOAPFaultException
public void throwSoapFaultException()
{
SOAPFactory factory = SOAPFactory.newInstance();
SOAPFault fault = factory.createFault("this is a fault string!", new QName("http://foo", "FooCode"));
fault.setFaultActor("mr.actor");
fault.addDetail().addChildElement("test");
throw new SOAPFaultException(fault);
}
or an application specific user exception
public void throwApplicationException() throws UserException
{
throw new UserException("validation", 123, "Some validation error");
}
Note
In case of the latter JBossWS generates the required fault wrapper beans at runtime if they are not part of the deployment
DataBinding
Using JAXB with non annotated classes
JAXB is heavily driven by Java Annotations on the Java Bindings. It currently doesn't support an external binding configuration. This recently became an issue for us on JBossESB since the JBossWS 2.0.0 native SOAP stack uses JAXB to perform the SOAP to Java bindings (see 1, 2). It's an issue for JBossESB simply because it needs to be able to support user definition of JBossWS native Webservice Endpoints (e.g. JSR 181) using Java typesets that have not been "JAXB Annotated" (see JAXB Introductions On JBossWS).
In order to support this, we built on a JAXB RI feature whereby it allows you to specify a RuntimeInlineAnnotationReader implementation during JAXBContext creation (see JAXBRIContext).
We call this feature "JAXB Annotation Introduction" and we've made it available for general consumption i.e. it can be checked out, built and used from SVN:
Complete documentation can be found here:
Mapping of xsd:any
Attachments
MTOM/XOP
This chapter describes Message Transmission Optimization Mechanism (MTOM) and XML-binary Optimized Packaging (XOP), a means of more efficiently serializing XML Infosets that have certain types of content. The related specifications are
Supported MTOM parameter types
| image/jpeg | java.awt.Image |
| text/xml | javax.xml.transform.Source |
| application/xml | javax.xml.transform.Source |
| application/octet-stream | javax.activation.DataHandler |
The above table shows a list of supported endpoint parameter types. The recommended approach is to use the javax.activation.DataHandler classes to represent binary data as service endpoint parameters.
Note
Microsoft endpoints tend to send any data as application/octet-stream. The only Java type that can easily cope with this ambiguity is javax.activation.DataHandler
Enabling MTOM per endpoint
On the server side MTOM processing is enabled through the @BindingType annotation. JBossWS does handle SOAP1.1 and SOAP1.2. Both come with or without MTOM flavours:
MTOM enabled service implementations
package org.jboss.test.ws.jaxws.samples.xop.doclit;
import javax.ejb.Remote;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.xml.ws.BindingType;
@Remote
@WebService(targetNamespace = "http://org.jboss.ws/xop/doclit")
@SOAPBinding(style = SOAPBinding.Style.DOCUMENT, parameterStyle = SOAPBinding.ParameterStyle.BARE)
@BindingType(value="http://schemas.xmlsoap.org/wsdl/soap/http?mtom=true") (1)
public interface MTOMEndpoint {
[...]
}
- The MTOM enabled SOAP 1.1 binding ID
MTOM enabled clients
Web service clients can use the same approach described above or rely on the Binding API to enable MTOM (Excerpt taken from the org.jboss.test.ws.jaxws.samples.xop.doclit.XOPTestCase):
[...] Service service = Service.create(wsdlURL, serviceName); port = service.getPort(MTOMEndpoint.class); // enable MTOM binding = (SOAPBinding)((BindingProvider)port).getBinding(); binding.setMTOMEnabled(true);
Note
You might as well use the JBossWS configuration templates to setup deployment defaults.
SwaRef
WS-I Attachment Profile 1.0 defines mechanism to reference MIME attachment parts using swaRef. In this mechanism the content of XML element of type wsi:swaRef is sent as MIME attachment and the element inside SOAP Body holds the reference to this attachment in the CID URI scheme as defined by RFC 2111.
Using SwaRef with JAX-WS endpoints
JAX-WS endpoints delegate all marshalling/unmarshalling to the JAXB API. The most simple way to enable SwaRef encoding for DataHandler types is to annotate a payload bean with the @XmlAttachmentRef annotation as shown below:
/**
* Payload bean that will use SwaRef encoding
*/
@XmlRootElement
public class DocumentPayload
{
private DataHandler data;
public DocumentPayload()
{
}
public DocumentPayload(DataHandler data)
{
this.data = data;
}
@XmlElement
@XmlAttachmentRef
public DataHandler getData()
{
return data;
}
public void setData(DataHandler data)
{
this.data = data;
}
}
With document wrapped endpoints you may even specify the @XmlAttachmentRef annotation on the service endpoint interface:
@WebService
public interface DocWrappedEndpoint
{
@WebMethod
DocumentPayload beanAnnotation(DocumentPayload dhw, String test);
@WebMethod
@XmlAttachmentRef
DataHandler parameterAnnotation(@XmlAttachmentRef DataHandler data, String test);
}
The message would then refer to the attachment part by CID:
<env:Envelope xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'> <env:Header/> <env:Body> <ns2:parameterAnnotation xmlns:ns2='http://swaref.samples.jaxws.ws.test.jboss.org/'> <arg0>cid:0-1180017772935-32455963@ws.jboss.org</arg0> <arg1>Wrapped test</arg1> </ns2:parameterAnnotation> </env:Body> </env:Envelope>
Starting from WSDL
If you chose the contract first approach then you need to ensure that any element declaration that should use SwaRef encoding simply refers to wsi:swaRef schema type:
<element name="data" type="wsi:swaRef" xmlns:wsi="http://ws-i.org/profiles/basic/1.1/xsd"/>
Any wsi:swaRef schema type would then be mapped to DataHandler.
Tools
JAX-WS tools
Please refer to JBossWS_JAX-WS_Tools for details. This covers directions on web service contract generation (bottom-up development) and consumption (top-down and client development).
Management tools
JBoss and its web service framework come with some tools allowing WS endpoint management.
Please refer the Endpoint management page for an overview of the available tools. In particular the Records management system gives administrators a means of performing custom analysis of their web service traffic as well as exporting communication logs.
Web Service Extensions
WS-Addressing
This section describes how WS-Addressing can be used to provide a stateful service endpoint.
Specifications
WS-Addressing is defined by a combination of the following specifications from the W3C Candidate Recommendation 17 August 2005. The WS-Addressing API is standardized by JSR-261 - Java API for XML Web Services Addressing
Addressing Endpoint
The following endpoint implementation has a set of operation for a typical stateful shopping chart application.
@WebService(name = "StatefulEndpoint", targetNamespace = "http://org.jboss.ws/samples/wsaddressing", serviceName = "TestService")
@EndpointConfig(configName = "Standard WSAddressing Endpoint")
@HandlerChain(file = "WEB-INF/jaxws-handlers.xml")
@SOAPBinding(style = SOAPBinding.Style.RPC)
public class StatefulEndpointImpl implements StatefulEndpoint, ServiceLifecycle
{
@WebMethod
public void addItem(String item)
{ ... }
@WebMethod
public void checkout()
{ ... }
@WebMethod
public String getItems()
{ ... }
}
It uses the Standard WSAddressing Endpoint to enable the server side addressing handler. It processes the incomming WS-Addressing header elements and provides access to them through the JSR-261 API.
The endpoint handler chain
<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 javaee_web_services_1_2.xsd">
<handler-chain>
<protocol-bindings>##SOAP11_HTTP</protocol-bindings>
<handler>
<handler-name>Application Server Handler</handler-name>
<handler-class>org.jboss.test.ws.jaxws.samples.wsaddressing.ServerHandler</handler-class>
</handler>
</handler-chain>
</handler-chains>
defines an application specific hander that assignes/processes stateful client ids.
Addressing Client
On the client side there are simmilar handlers that does the reverse. It uses the JSR-261 API to add WS-Addressing header elements including the clientid association.
The client sets a custom handler chain in the binding
Service service = Service.create(wsdlURL, serviceName);
port1 = (StatefulEndpoint)service.getPort(StatefulEndpoint.class);
BindingProvider bindingProvider = (BindingProvider)port1;
List<Handler> customHandlerChain = new ArrayList<Handler>();
customHandlerChain.add(new ClientHandler());
customHandlerChain.add(new WSAddressingClientHandler());
bindingProvider.getBinding().setHandlerChain(customHandlerChain);
The WSAddressingClientHandler is provided by JBossWS and reads/writes the addressing properties and puts then into the message context.
A client connecting to the stateful endpoint
public class AddressingStatefulTestCase extends JBossWSTest
{
public void testAddItem() throws Exception
{
port1.addItem("Ice Cream");
port1.addItem("Ferrari");
port2.addItem("Mars Bar");
port2.addItem("Porsche");
}
public void testGetItems() throws Exception
{
String items1 = port1.getItems();
assertEquals("[Ice Cream, Ferrari]", items1);
String items2 = port2.getItems();
assertEquals("[Mars Bar, Porsche]", items2);
}
}
SOAP message exchange
Below you see the SOAP messages that are beeing exchanged.
<env:Envelope xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'>
<env:Header xmlns:wsa='http://schemas.xmlsoap.org/ws/2004/08/addressing'>
<wsa:To>uri:jbossws-samples-wsaddr/TestService</wsa:To>
<wsa:Action>http://org.jboss.ws/addressing/stateful/action</wsa:Action>
<wsa:ReferenceParameters>
<ns1:clientid xmlns:ns1='http://somens'>clientid-1</ns1:clientid>
</wsa:ReferenceParameters>
</env:Header>
<env:Body>
<ns1:addItem xmlns:ns1='http://org.jboss.ws/samples/wsaddr'>
<String_1>Ice Cream</String_1>
</ns1:addItem>
</env:Body>
</env:Envelope>
<env:Envelope xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'>
<env:Header xmlns:wsa='http://schemas.xmlsoap.org/ws/2004/08/addressing'>
<wsa:To>http://www.w3.org/2005/08/addressing/anonymous</wsa:To>
<wsa:Action>http://org.jboss.ws/addressing/stateful/actionReply</wsa:Action>
<ns1:clientid xmlns:ns1='http://somens'>clientid-1</ns1:clientid>
</env:Header>
<env:Body>
<ns1:addItemResponse xmlns:ns1='http://org.jboss.ws/samples/wsaddr'/>
</env:Body>
</env:Envelope>
...
<env:Envelope xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'>
<env:Header xmlns:wsa='http://schemas.xmlsoap.org/ws/2004/08/addressing'>
<wsa:To>uri:jbossws-samples-wsaddr/TestService</wsa:To>
<wsa:Action>http://org.jboss.ws/addressing/stateful/action</wsa:Action>
<wsa:ReferenceParameters>
<ns1:clientid xmlns:ns1='http://somens'>clientid-1</ns1:clientid>
</wsa:ReferenceParameters>
</env:Header>
<env:Body>
<ns1:getItems xmlns:ns1='http://org.jboss.ws/samples/wsaddr'/>
</env:Body>
</env:Envelope>
<env:Envelope xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'>
<env:Header xmlns:wsa='http://schemas.xmlsoap.org/ws/2004/08/addressing'>
<wsa:To>http://www.w3.org/2005/08/addressing/anonymous</wsa:To>
<wsa:Action>http://org.jboss.ws/addressing/stateful/actionReply</wsa:Action>
<ns1:clientid xmlns:ns1='http://somens'>clientid-1</ns1:clientid>
</env:Header>
<env:Body>
<ns1:getItemsResponse xmlns:ns1='http://org.jboss.ws/samples/wsaddr'>
<result>[Ice Cream, Ferrari]</result>
</ns1:getItemsResponse>
</env:Body>
</env:Envelope>
Tutorial
For further details please take a look at our WS-Addressing Tutorial.
WS-BPEL
WS-BPEL is not supported with JAX-WS, please refer to JAX-RPC User Guide#WS-BPEL.
WS-Eventing
WS-Eventing specifies a set of operations that allow an event consumer to register (subscribe) with an event producer (source) to receive events (notifications) in an asynchronous fashion.
Specifications
WS-Eventing is defined by the combination of the following specifications:
The following section will introduce the main eventing actors and their responsiblities.
Note
The original eventing specification builds upon WS-Addressing 2004/08. JBossWS however decided to stick to the latest version, which is the W3C candidate release.
Collaboration
- An event sink (web service client) sends a subscribtion request to the event source endpoint. This includes the event sink endpoint address where notifications should delivered. Upon successful subscription the sink receives a leased subscription ID that can be used to identify the client in subsequent requests.
- A successfully registered event sink directs management requests (Renew, GetStatus, Unsubscribe) to the subscription manager endpoint using the previously received subscription ID. The subscription manager endpoint address was returned as part of the subscription response in the first place.
- The actual event sink (application) emits notification messages through the JBossWS-Eventing module. JBossWS-Eventing dispatches the notification to any subscriber endpoint that is registered with a particular event source.s
- Besides notifications JBossWS-Eventing may emit lifecycle events at any time, i.e. to inform an event sink that a subscription was canceled. This can be the case when the subscription expired or the event source was undeployed.
It is the users responsibilty to supply the web service endpoints (EventSourceEndpoint, SubscriptionManagerEndpoint) that are required for a complete event source deployment. Fortunatly JBossWS-Eventing already ships with a implementation that can be used right away. All that's left todo is packaging of standard JSR-109 deployment archive that includes the event source specific WSDL and points to the JBossWS-Eventing endpoint implementations.
The relevant steps are:
- Create a custom WSDL that describes your event source, in respect to the notification schema (1) and the fact that is actually contains an event source port (2)
- Use the JBossWS SEI (3) and endpoint (4) implementations (web.xml).
Setup an event source endpoint
With JAX-WS the event source setup has actually become quiet easy. All you need to do is to subclass your endpoint implementation from AbstractEventSourceEndpoint and a subscription manager from AbstractSubscriptionManagerEndpoint and finally point that implementation to a event source specific WSDL.
package org.jboss.test.ws.jaxws.samples.wseventing;
import javax.jws.WebService;
import org.jboss.logging.Logger;
import org.jboss.ws.annotation.EndpointConfig;
import org.jboss.ws.extensions.eventing.jaxws.AbstractEventSourceEndpoint;
/**
* @author Heiko.Braun@jboss.org
* @version $Id$
* @since 18.01.2007
*/
@WebService( (1)
name = "EventSource",
portName = "EventSourcePort",
targetNamespace = "http://schemas.xmlsoap.org/ws/2004/08/eventing",
wsdlLocation = "/WEB-INF/wsdl/sysmon.wsdl", (2)
endpointInterface = "org.jboss.ws.extensions.eventing.jaxws.EventSourceEndpoint")
@EndpointConfig(configName = "Standard WSAddressing Endpoint") (3)
public class SysmonRegistrationEndpoint extends AbstractEventSourceEndpoint { (4)
private static final Logger log = Logger.getLogger(SysmonRegistrationEndpoint.class);
protected Logger getLogger()
{
return log;
}
}
- Of course we need a @WebService annotation
- It's important to override the WSDL here
- You need to tell JBossWS that it requires WS-Addressing for this endpoint
- Subclass a predefined implementation that knows how to delegate to the actual eventing service implementation
The WSDL that describes an event source
Even though we are already using the annotation driven approach, JBossWS eventing still requires an event source specific WSDL.
The following excerpt shows the relevant WSDL details that describe an event source.
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions
targetNamespace="http://www.jboss.org/sysmon"
xmlns:tns="http://www.jboss.org/sysmon"
xmlns:wse='http://schemas.xmlsoap.org/ws/2004/08/eventing'
xmlns:wsdl='http://schemas.xmlsoap.org/wsdl/'
xmlns:wsa10='http://www.w3.org/2005/08/addressing'
xmlns:xs='http://www.w3.org/2001/XMLSchema'
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
<wsdl:import
(1) namespace='http://schemas.xmlsoap.org/ws/2004/08/eventing'
location='jbwse.wsdl' />
<wsdl:types>
<xs:schema targetNamespace='http://schemas.xmlsoap.org/ws/2004/08/eventing'>
(2) <xs:include schemaLocation='jbwse.xsd'/>
</xs:schema>
(3) <xs:schema
targetNamespace="http://www.jboss.org/sysmon"
elementFormDefault="qualified"
blockDefault="#all">
<xs:element name="SystemStatus">
<xs:complexType>
<xs:sequence>
<xs:element name="Time " type="xs:dateTime"/>
<xs:element name="HostName" type="xs:string"/>
<xs:element name="HostAddress" type="xs:string"/>
<xs:element name="ActiveThreadCount" type="xs:int"/>
<xs:element name="FreeMemory" type="xs:string"/>
<xs:element name="MaxMemory" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
</wsdl:types>
<wsdl:message name='SystemInfoMsg'>
<wsdl:part name='body' element='tns:SystemStatus'/>
</wsdl:message>
(4) <wsdl:portType name='SystemInfo' wse:EventSource='true'>
<wsdl:operation name='SysmonOp'>
<wsdl:output message='tns:SystemInfoMsg'/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="SystemInfoBinding" type="tns:SystemInfo">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="SysmonOp">
<soap:operation soapAction=""/>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
</wsdl:definitions>
- Import the default eventing WSDL, that includes service and port declarations.
- Include the default eventing Types
- Specifiy the notitification message schema.
- Declare a port type, attributed "wse:EventSource='true'" that points to your notification message schema.
Emitting notifications
JBossWS-Eventing registeres a event dispatcher within local JNDI tree that can be used to emit notifications from applications.
java:/EventDispatcher
The event dispatcher interface:
public interface EventDispatcher
{
void dispatch(URI eventSourceNS, Element payload);
}
Example notification
(1) URI eventSourceURI = new URI("http://http://www.jboss.org/sysmon/SystemInfo");
(2) Element payload = DOMUtils.parse("SOME XML STRING");
try
{
InitialContext iniCtx = getInitialContext();
(3) EventDispatcher delegate = (EventDispatcher)
iniCtx.lookup(EventingConstants.DISPATCHER_JNDI_NAME);
(4) delegate.dispatch(eventSourceURI, payload);
}
catch (Exception e)
{
//
}
- Address your event source correctly (TargetNamespace+PortTypeName)
- Create your payload
- Lookup dispatcher from JNDI
- Dispatch notification.
jboss.ws.eventing:service=SubscriptionManager
Management operations exist to monitor and maintain active subscritions and deployed event sources. The current implementation is backed by a ThreadPoolExecutor, that asynchronously delivers messages to event sink endpoints. It can be configured through the following attributes:
- corePoolSize - average number of idle threads
- maximumPoolSize - maximum number of threads
- eventKeepAlive - keep alive before an undelivered event message is discarded.
WS-Security
WS-Security addresses message level security. It standardizes authorization, encryption, and digital signature processing of web services. Unlike transport security models, such as SSL, WS-Security applies security directly to the elements of the web service message. This increases the flexibility of your web services, by allowing any message model to be used (point to point, multi-hop relay, etc).
This chapter describes how to use WS-Security to sign and encrypt a simple SOAP message.
Specifications
WS-Security is defined by the combination of the following specifications:
- SOAP Message Security 1.0
- Username Token Profile 1.0
- X.509 Token Profile 1.0
- W3C XML Encryption
- W3C XML Signature
- Basic Security Profile 1.0 (Still in Draft)
Endpoint configuration
JBossWS uses handlers to identify ws-security encoded requests and invoke the security components to sign and encrypt messages. In order to enable security processing, the client and server side need to include a corresponding handler configuration. The preferred way is to reference a predefined JAX-WS_Endpoint_Configuration or JAX-WS_Client_Configuration respectively.
Note
You need to setup both the endpoint configuration and the WSSE declarations. That's two separate steps.
Server side WSSE declaration (jboss-wsse-server.xml)
In this example we configure both the client and the server to sign the message body. Both also require this from each other. So, if you remove either the client or the server security deployment descriptor, you will notice that the other party will throw a fault explaining that the message did not conform to the proper security requirements.
<jboss-ws-security xmlns="http://www.jboss.com/ws-security/config"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.jboss.com/ws-security/config
http://www.jboss.com/ws-security/schema/jboss-ws-security_1_0.xsd">
(1) <key-store-file>WEB-INF/wsse.keystore</key-store-file>
(2) <key-store-password>jbossws</key-store-password>
(3) <trust-store-file>WEB-INF/wsse.truststore</trust-store-file>
(4) <trust-store-password>jbossws</trust-store-password>
(5) <config>
(6) <sign type="x509v3" alias="wsse"/>
(7) <requires>
(8) <signature/>
</requires>
</config>
</jboss-ws-security>
- This specifies that the key store we wish to use is WEB-INF/wsse.keystore, which is located in our war file.
- This specifies that the store password is "jbossws". Password can be encypted using the {EXT} and {CLASS} commands. Please see samples for their usage.
- This specifies that the trust store we wish to use is WEB-INF/wsse.truststore, which is located in our war file.
- This specifies that the trust store password is also "jbossws". Password can be encrypted using the {EXT} and {CLASS} commands. Please see samples for their usage.
- Here we start our root config block. The root config block is the default configuration for all services in this war file.
- This means that the server must sign the message body of all responses. Type means that we are to use a X.509v3 certificate (a standard certificate). The alias option says that the certificate/key pair to use for signing is in the key store under the "wsse" alias
- Here we start our optional requires block. This block specifies all security requirements that must be met when the server receives a message.
- This means that all web services in this war file require the message body to be signed.
By default an endpoint does not use the WS-Security configuration. Use the proprietary @EndpointConfig annotation to set the config name. See JAX-WS_Endpoint_Configuration for the list of available config names.
@WebService
@EndpointConfig(configName = "Standard WSSecurity Endpoint")
public class HelloJavaBean
{
...
}
Client side WSSE declaration (jboss-wsse-client.xml)
<jboss-ws-security xmlns="http://www.jboss.com/ws-security/config"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.jboss.com/ws-security/config
http://www.jboss.com/ws-security/schema/jboss-ws-security_1_0.xsd">
(1) <config>
(2) <sign type="x509v3" alias="wsse"/>
(3) <requires>
(4) <signature/>
</requires>
</config>
</jboss-ws-security>
- Here we start our root config block. The root config block is the default configuration for all web service clients (Call, Proxy objects).
- This means that the client must sign the message body of all requests it sends. Type means that we are to use a X.509v3 certificate (a standard certificate). The alias option says that the certificate/key pair to use for signing is in the key store under the "wsse" alias
- Here we start our optional requires block. This block specifies all security requirements that must be met when the client receives a response.
- This means that all web service clients must receive signed response messages.
Client side key store configuration
We did not specify a key store or trust store, because client app uses the WSSE System properties instead. If this was a Web or EJB client (meaning a webservice client in a war or EJB jar file), then we would have to specify them in the client descriptor.
Here is an excerpt from the JBossWS samples:
<sysproperty key="org.jboss.ws.wsse.keyStore"
value="${tests.output.dir}/resources/jaxrpc/samples/wssecurity/wsse.keystore"/>
<sysproperty key="org.jboss.ws.wsse.trustStore"
value="${tests.output.dir}/resources/jaxrpc/samples/wssecurity/wsse.truststore"/>
<sysproperty key="org.jboss.ws.wsse.keyStorePassword" value="jbossws"/>
<sysproperty key="org.jboss.ws.wsse.trustStorePassword" value="jbossws"/>
<sysproperty key="org.jboss.ws.wsse.keyStoreType" value="jks"/>
<sysproperty key="org.jboss.ws.wsse.trustStoreType" value="jks"/>
SOAP message exchange
Below you see the incomming SOAP message with the details of the security headers ommited. The idea is, that the SOAP body is still plain text, but it is signed in the security header and can therefore not manipulated in transit.
Incomming SOAPMessage
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Header>
<wsse:Security env:mustUnderstand="1" ...>
<wsu:Timestamp wsu:Id="timestamp">...</wsu:Timestamp>
<wsse:BinarySecurityToken ...>
...
</wsse:BinarySecurityToken>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
...
</ds:Signature>
</wsse:Security>
</env:Header>
<env:Body wsu:Id="element-1-1140197309843-12388840" ...>
<ns1:echoUserType xmlns:ns1="http://org.jboss.ws/samples/wssecurity">
<UserType_1 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<msg>Kermit</msg>
</UserType_1>
</ns1:echoUserType>
</env:Body>
</env:Envelope>
Installing the BouncyCastle JCE provider (JDK 1.4)
The information below has originaly been provided by The Legion of the Bouncy Castle.
The provider can be configured as part of your environment via static registration by adding an entry to the java.security properties file (found in $JAVA_HOME/jre/lib/security/java.security, where $JAVA_HOME is the location of your JDK/JRE distribution). You'll find detailed instructions in the file but basically it comes down to adding a line:
security.provider.<n>=org.bouncycastle.jce.provider.BouncyCastleProvider
Where <n> is the preference you want the provider at.
Note
Issues may arise if the Sun providers are not first.
Where you put the jar is mostly up to you, although with jdk1.4 the best (and in some cases only) place to have it is in $JAVA_HOME/jre/lib/ext. Under Windows there will normally be a JRE and a JDK install of Java if you think you have installed it correctly and it still doesn't work chances are you have added the provider to the installation not being used.
Keystore, truststore - What?
Note
If you having a hard time understanding how the different trust- and keystore configurations are used for signature and encryption, then read this thread first: http://www.jboss.org/index.html?module=bb&op=viewtopic&t=94406
Advanced configuration
Further information and examples covering advanced WS-Security configuration options are available. Those might help when specific settings are required to obtain interoperability with other vendors' WS-Security implementation.
WS-Reliable Messaging
WS-Reliable Messaging specifies how a reliable web service communication can be achieved.
Please take a look at our WS-Reliable Messaging Tutorial for configuration details.
WS-Transaction
Support for the WS-Coordination, WS-AtomicTransaction and WS-BusinessActivity specifications will be provided by technology recently acquired from Arjuna Technologies Ltd. This technology will be present within the JBoss Transactions 4.2.1 release. Further information can be obtained from the JBoss Transactions Project
XML Registries
J2EE 1.4 mandates support for Java API for XML Registries (JAXR). Inclusion of a XML Registry with the J2EE 1.4 certified Application Server is optional. Starting jboss-4.0.2, JBoss ships a UDDI v2.0 compliant registry, the Apache jUDDI registry. We also provide support for JAXR Capability Level 0 (UDDI Registries) via integration of Apache Scout.
This chapter describes how to configure the jUDDI registry in JBoss and some sample code outlines for using JAXR API to publish and query the jUDDI registry.
Apache jUDDI Configuration
Configuration of the jUDDI registry happens via an MBean Service that is deployed in the juddi-service.sar archive in the "all" configuration. The configuration of this service can be done in the jboss-service.xml of the META-INF directory in the juddi-service.sar
Let us look at the individual configuration items that can be changed.
DataSources configuration
<!-- Datasource to Database-->
<attribute name="DataSourceUrl">java:/DefaultDS</attribute>
Database Tables (Should they be created on start, Should they be dropped on stop, Should they be dropped on start etc)
<!-- Should all tables be created on Start-->
<attribute name="CreateOnStart">false</attribute>
<!-- Should all tables be dropped on Stop-->
<attribute name="DropOnStop">true</attribute>
<!-- Should all tables be dropped on Start-->
<attribute name="DropOnStart">false</attribute>
JAXR Connection Factory to be bound in JNDI. (Should it be bound? and under what name?)
<!-- Should I bind a Context to which JaxrConnectionFactory bound-->
<attribute name="ShouldBindJaxr">true</attribute>
<!-- Context to which JaxrConnectionFactory to bind to. If you have remote clients, please bind it to the global namespace(default behavior).
To just cater to clients running on the same VM as JBoss, change to java:/JAXR -->
<attribute name="BindJaxr">JAXR</attribute>
Other common configuration:
Add authorized users to access the jUDDI registry. (Add a sql insert statement in a single line)
Look at the script META-INF/ddl/juddi_data.ddl for more details. Example for a user 'jboss'
INSERT INTO PUBLISHER (PUBLISHER_ID,PUBLISHER_NAME,
EMAIL_ADDRESS,IS_ENABLED,IS_ADMIN)
VALUES ('jboss','JBoss User','jboss@xxx','true','true');
JBoss JAXR Configuration
In this section, we will discuss the configuration needed to run the JAXR API. The JAXR configuration relies on System properties passed to the JVM. The System properties that are needed are:
javax.xml.registry.ConnectionFactoryClass=org.apache.ws.scout.registry.ConnectionFactoryImpl jaxr.query.url=http://localhost:8080/juddi/inquiry jaxr.publish.url=http://localhost:8080/juddi/publish juddi.proxy.transportClass=org.jboss.jaxr.juddi.transport.SaajTransport
Please remember to change the hostname from "localhost" to the hostname of the UDDI service/JBoss Server.
You can pass the System Properties to the JVM in the following ways:
- When the client code is running inside JBoss (maybe a servlet or an EJB). Then you will need to pass the System properties in the run.sh/run.bat scripts to the java process via the "-D" option.
- When the client code is running in an external JVM. Then you can pass the properties either as "-D" options to the java process or explicitly set them in the client code(not recommended).
System.setProperty(propertyname, propertyvalue);
JAXR Sample Code
There are two categories of API: JAXR Publish API and JAXR Inquiry API. The important JAXR interfaces that any JAXR client code will use are the following.
- javax.xml.registry.RegistryService From J2EE 1.4 JavaDoc: "This is the principal interface implemented by a JAXR provider. A registry client can get this interface from a Connection to a registry. It provides the methods that are used by the client to discover various capability specific interfaces implemented by the JAXR provider."
- javax.xml.registry.BusinessLifeCycleManager From J2EE 1.4 JavaDoc: "The BusinessLifeCycleManager interface, which is exposed by the Registry Service, implements the life cycle management functionality of the Registry as part of a business level API. Note that there is no authentication information provided, because the Connection interface keeps that state and context on behalf of the client."
- javax.xml.registry.BusinessQueryManager From J2EE 1.4 JavaDoc: "The BusinessQueryManager interface, which is exposed by the Registry Service, implements the business style query interface. It is also referred to as the focused query interface."
Let us now look at some of the common programming tasks performed while using the JAXR API:
Getting a JAXR Connection to the registry.
String queryurl = System.getProperty("jaxr.query.url", "http://localhost:8080/juddi/inquiry");
String puburl = System.getProperty("jaxr.publish.url", "http://localhost:8080/juddi/publish");
Properties props = new Properties();
props.setProperty("javax.xml.registry.queryManagerURL", queryurl);
props.setProperty("javax.xml.registry.lifeCycleManagerURL", puburl);
String transportClass = System.getProperty("juddi.proxy.transportClass", "org.jboss.jaxr.juddi.transport.SaajTransport");
System.setProperty("juddi.proxy.transportClass", transportClass);
// Create the connection, passing it the configuration properties
factory = ConnectionFactory.newInstance();
factory.setProperties(props);
connection = factory.createConnection();
Authentication with the registry.
/**
* Does authentication with the uddi registry
*/
protected void login() throws JAXRException
{
PasswordAuthentication passwdAuth = new PasswordAuthentication(userid, passwd.toCharArray());
Set creds = new HashSet();
creds.add(passwdAuth);
connection.setCredentials(creds);
}
Save a Business
/**
* Creates a Jaxr Organization with 1 or more services
*/
protected Organization createOrganization(String orgname) throws JAXRException
{
Organization org = blm.createOrganization(getIString(orgname));
org.setDescription(getIString("JBoss Inc"));
Service service = blm.createService(getIString("JBOSS JAXR Service"));
service.setDescription(getIString("Services of XML Registry"));
//Create serviceBinding
ServiceBinding serviceBinding = blm.createServiceBinding();
serviceBinding.setDescription(blm.createInternationalString("Test Service Binding"));
//Turn validation of URI off
serviceBinding.setValidateURI(false);
serviceBinding.setAccessURI("http://testjboss.org");
// Add the serviceBinding to the service
service.addServiceBinding(serviceBinding);
User user = blm.createUser();
org.setPrimaryContact(user);
PersonName personName = blm.createPersonName("Anil S");
TelephoneNumber telephoneNumber = blm.createTelephoneNumber();
telephoneNumber.setNumber("111-111-7777");
telephoneNumber.setType(null);
PostalAddress address = blm.createPostalAddress("111", "My Drive", "BuckHead", "GA", "USA", "1111-111", "");
Collection postalAddresses = new ArrayList();
postalAddresses.add(address);
Collection emailAddresses = new ArrayList();
EmailAddress emailAddress = blm.createEmailAddress("anil@apache.org");
emailAddresses.add(emailAddress);
Collection numbers = new ArrayList();
numbers.add(telephoneNumber);
user.setPersonName(personName);
user.setPostalAddresses(postalAddresses);
user.setEmailAddresses(emailAddresses);
user.setTelephoneNumbers(numbers);
ClassificationScheme cScheme = getClassificationScheme("ntis-gov:naics", "");
Key cKey = blm.createKey("uuid:C0B9FE13-324F-413D-5A5B-2004DB8E5CC2");
cScheme.setKey(cKey);
Classification classification = blm.createClassification(cScheme, "Computer Systems Design and Related Services", "5415");
org.addClassification(classification);
ClassificationScheme cScheme1 = getClassificationScheme("D-U-N-S", "");
Key cKey1 = blm.createKey("uuid:3367C81E-FF1F-4D5A-B202-3EB13AD02423");
cScheme1.setKey(cKey1);
ExternalIdentifier ei = blm.createExternalIdentifier(cScheme1, "D-U-N-S number", "08-146-6849");
org.addExternalIdentifier(ei);
org.addService(service);
return org;
}
Query a Business
/**
* Locale aware Search a business in the registry
*/
public void searchBusiness(String bizname) throws JAXRException
{
try
{
// Get registry service and business query manager
this.getJAXREssentials();
// Define find qualifiers and name patterns
Collection findQualifiers = new ArrayList();
findQualifiers.add(FindQualifier.SORT_BY_NAME_ASC);
Collection namePatterns = new ArrayList();
String pattern = "%" + bizname + "%";
LocalizedString ls = blm.createLocalizedString(Locale.getDefault(), pattern);
namePatterns.add(ls);
// Find based upon qualifier type and values
BulkResponse response = bqm.findOrganizations(findQualifiers, namePatterns, null, null, null, null);
// check how many organisation we have matched
Collection orgs = response.getCollection();
if (orgs == null)
{
log.debug(" -- Matched 0 orgs");
}
else
{
log.debug(" -- Matched " + orgs.size() + " organizations -- ");
// then step through them
for (Iterator orgIter = orgs.iterator(); orgIter.hasNext();)
{
Organization org = (Organization)orgIter.next();
log.debug("Org name: " + getName(org));
log.debug("Org description: " + getDescription(org));
log.debug("Org key id: " + getKey(org));
checkUser(org);
checkServices(org);
}
}
}
finally
{
connection.close();
}
}
For more examples of code using the JAXR API, please refer to the resources in the Resources Section.
Trouble Shooting
- I cannot connect to the registry from JAXR. Please check the inquiry and publish url passed to the JAXR ConnectionFactory.
- I cannot connect to the jUDDI registry. Please check the jUDDI configuration and see if there are any errors in the server.log. And also remember that the jUDDI registry is available only in the "all" configuration.
- I cannot authentica


