Default Behavior
In JAX-WS reference implementation, 'wsimport' defaults to wrapper doc/lit style when generating Java classes from WSDL. In doing so, the generated 'PortType' interface class sometimes uses 'javax.xml.ws.Holder' class as input parameters extensively. For example,
public void startOperation(
XMLGregorianCalendar eventTime,
OpConfigs opConfigs,
Location location,
Holder<String> status,
Holder<String> description) {
// TODO Auto-generated method stub
return null;
}
}
Disable Wrapper Style
You can use a custom binding file to disable the default wrapper style as follows if you need to.
* Create a custom binding file, e.g. CustomBinding.xml.
<bindings
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
wsdlLocation="OperationService.wsdl"
xmlns="http://java.sun.com/xml/ns/jaxws">
<!-- Disable default wrapper style -->
<enableWrapperStyle>false</enableWrapperStyle>
</bindings>
* Including 'binding' element in 'wsimport' Ant task.
<wsimport
debug="true"
verbose="${verbose}"
keep="true"
destdir="${generated.dir}"
package="${src.pkg.name}.server"
wsdl="${wsdl.file}">
<binding dir="${basedir}/etc"
includes="CustomBinding.xml"/>
</wsimport>
After setting 'enableWrapperStyle' to false, the same generated operation name in PortType class becomes:
public Response startOperation(TStartOperation parameters) {
// TODO Auto-generated method stub
return null;
}
For Simpler and Better Typed Binding
* Create a new JAXB binding file, e.g. simple.xjb:
<?xml version="1.0" encoding="UTF-8"?>
<!--
This enables the simple binding mode in JAXB.
See http://weblogs.java.net/blog/kohsuke/archive/2006/03/simple_and_bett.html
-->
<jaxb:bindings
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" jaxb:version="2.0"
xmlns:xjc= "http://java.sun.com/xml/ns/jaxb/xjc" jaxb:extensionBindingPrefixes="xjc">
<jaxb:globalBindings>
<xjc:simple />
</jaxb:globalBindings>
</jaxb:bindings>
* Specify in wsimport Ant task:
<wsimport
debug="true"
verbose="${verbose}"
keep="true"
destdir="${generated.dir}"
package="${src.pkg.name}.server"
wsdl="${wsdl.file}">
<binding dir="${basedir}/etc"
includes="CustomBinding.xml,simple.xjb"/>
</wsimport>
* The operation now looks like this:
public Response startOperation(StartOperation parameters) {
// TODO Auto-generated method stub
return null;
}
Parameter name 'StartOperation' is more readable now among benefits.
References
* jaxws-ri/docs/customizations.html
* Wrapper Style
* Customizing XML Schema binding
Filed under: jax-ws | |Comments off
Apache WS Evolution
First generation: Apache SOAP
Second generation: Axis
Third generation: Axis2
Axis2 Architecture
Core Modules
XML Processing Module
*AXIOM (Axis Object Model)
- Based on PULL parser so more control over XML parsing
SOAP Processing Module
* Handlers: intercept and process part of SOAP message
- Three scopes: global, service, operation scope
* Phases: logical collection of one or more handlers
- They're handler containers
- They also order handlers
* Pipers
- InFlow
~ Last handler is Message Receiver
- OutFlow
Information Processing Module
* Description hierarchy: comes from deployment descriptors
Configuration<>-ServiceGroup<>-Service<>-Operation<>-Message
* Context hierarchy: keeps run-time data
ConfigurationContext<>-ServiceGroupContext<>-ServiceContext<>-OperationContext<>-MessageContext
Deployment Module
* Axis2 supports:
- Hot deployment
- Hot update
* Service extension by modules
A module contains:
- Handlers
- Third party libraries
- Module related resources
- Moduel config file (module.xml)
A module can be deployed as a .mar file
* Axis2 can be deployed as
- Archive file: a .aar file
- POJO deployment
- Custom deployer
Client API Module
* ServiceClient API: used to access SOAP body (payload)
sendRobust(): one way but traps exception
fireAndForget(): one way and don't care exception
sendReceive(): sunc two way
sendReceiveNonBlocking(): async two way
* OperationClient API: used to modify SOAP header
Create ServiceClient -> Create OperationClient -> Create SOAPEnvelope -> Create MessageContext -> Add SOAPEnvelope to MessageContext -> Add MessageContext to OperationClient -> Invoke OperationClient - (if response) -> Get response MessageContext form OperationClient
Transport Module
Supports:
* HTTP/HTTPS
* TCP: needs WS-Addressing
* SMTP
* JMS
* XMPP
Non Core Modules
Code Generation Module
Data Binding Module
Supports
* ADB (Axiss Data Binding)
* XMLBeans
* JaxMe: included in XMLBeans
* JibX

Axis2 Code Generation
Filed under: java, jax-ws | |Comments off
If the "cn" of the web services server certificate does not match its host name, you'll get:
com.sun.xml.ws.client.ClientTransportException: HTTP transport error: java.io.IOException: HTTPS hostname wrong: should be <mysite.com>
You can implement your own javax.net.ssl.HostnameVerifier to suppress it. Important, remember to remove the codes for production!
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;
public class TestHostnameVerifier implements HostnameVerifier {
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
}
In client code:
// Make sure java.protocol.handler.pkgs is set to "javax.net.ssl"
//System.setProperty( "java.protocol.handler.pkgs", "com.sun.net.ssl.internal.www.protocol" );
System.setProperty( "java.protocol.handler.pkgs", "javax.net.ssl" );
Security.addProvider( new com.sun.net.ssl.internal.ssl.Provider() );
HelloService service = new HelloService();
HelloPort proxy = service.getHelloPort();
Map<String, Object> ctxt = ((BindingProvider)proxy ).getRequestContext();
ctxt.put(JAXWSProperties.HTTP_CLIENT_STREAMING_CHUNK_SIZE, 8192);
ctxt.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, "https://new/endpointaddress");
ctxt.put(JAXWSProperties.HOSTNAME_VERIFIER, new TestHostnameVerifier());
proxy.sayHello("Hello World!");
Filed under: jax-ws, security | |No Comments
try {
HelloService service = new HelloService (
new URL("http://new/endpointaddress?wsdl"),
new QName("http://example.org/hello", "HelloService "));
} catch (MalformedURLException e) {
log.fatal(e);
}
HelloPort proxy = service.getHelloPort();
proxy.sayHello("Hello World!");
You can also use BindingProvider.ENDPOINT_ADDRESS_PROPERTY to override endpoint address. One caveat is the original endpoint used to generated the client proxy need to be up, otherwise you'll get a nasty "java.net.ConnectException: Connection refused" exception when instantiating the Service at the first place.
//Create service and proxy from the generated Service class.
HelloService service = new HelloService();
HelloPort proxy = service.getHelloPort();
Map<String, Object> ctxt = ((BindingProvider)proxy ).getRequestContext();
ctxt.put(JAXWSProperties.HTTP_CLIENT_STREAMING_CHUNK_SIZE, 8192);
ctxt.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, "http://new/endpointaddress");
proxy.sayHello("Hello World!");
Use a local wsdl placed in classpath to create service and port, then set new end point address. This solves the issue that the original wsdl can NOT be be obtained from a live server and the live wsdl has a different service name, for example as a result of service virtualization.
HelloService service = new HelloService (
this.getClass().getResource("originalHello.wsdl"),
new QName("http://example.org/hello", "HelloService "));
Map<String, Object> ctxt = ((BindingProvider)proxy ).getRequestContext();
ctxt.put(JAXWSProperties.HTTP_CLIENT_STREAMING_CHUNK_SIZE, 8192);
ctxt.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, "http://new/endpointaddress");
proxy.sayHello("Hello World!");
Filed under: jax-ws | |No Comments