Sun
JAX-WS is the webservice implementation from sun. While studying for my Sun
Webservice certification as well in my day to day work I do use Sun JAX-WS implementation. Compare to other webservice implementation JAX-WS performs better as well by default included with Java 1.6 version.
Webservice's normaly use SOAP-XML communication (http tuneling etc). But it's not fully enough now days. For example JSON webservice communication is more demanding. Using json web-service, Web-browsers can directly communicate with endpoints. Same like depends on application the way we like to communcate with webservice end point differ, following is short list of possible communication format.
- SOAP-XML.
- JSON.
- SMTP
- SQL.
To make any format of communication we need coder/decoder (Codec). so that it can convert the input/output as application readable or required format.
In this blog, I am going to explain how to write custom Codec for JAX-WS implementation in 10 steps.
Step 1: Create Project structure.
I do use eclipse with webtools as IDE. Create new J2ee utility project.
Eclipse create source and META-INF folder for you. After creating project add JAX-WS ri jars (webservices-api.jar,webservices-rt-1.3-SNAPSHOT.jar,webservices-tools.jar)into your project classpath. You can get this jars as part of java.net metro
MetroStep 2: Create XXXContentType.
First define communincation Content-Type. For example json its "application/json".
XXXContentType class implements "com.sun.xml.ws.api.pipe.ContentType" interface.
ContentType inteface contains 3 methods getAcceptHeader,
getContentType, and getSOAPActionHeader. All are self explained.
Step 3: Create XXXCodec
This is a main programing part of writing custom codec. You have to write serialization and deserialisation of java objects in this step.
Create a XXXCodec class implements from EndpointAwareCodec, EndpointComponent. methods implements from interface are self explanatory.
You have to write your decode and encode logic in respective methods.
While decoding read input data from InputStream and create "com.sun.xml.ws.api.message.Message" object and set it in package. Same like while encoding serialize java object into XXX content format and write in output stream.
package com.jaxws.codec;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import com.sun.xml.ws.api.SOAPVersion;
import com.sun.xml.ws.api.WSBinding;
import com.sun.xml.ws.api.message.Message;
import com.sun.xml.ws.api.message.Messages;
import com.sun.xml.ws.api.message.Packet;
import com.sun.xml.ws.api.pipe.Codec;
import com.sun.xml.ws.api.pipe.ContentType;
import com.sun.xml.ws.api.server.EndpointAwareCodec;
import com.sun.xml.ws.api.server.EndpointComponent;
import com.sun.xml.ws.api.server.WSEndpoint;
public class XXXCodec implements EndpointAwareCodec, EndpointComponent {
private static final ContentType xxxContentType = new XXXContentType();
private final WSBinding binding;
private WSEndpoint endpoint;
public XXXCodec(XXXCodec copy) {
this(copy.binding);
this.endpoint = copy.endpoint;
}
public XXXCodec(WSBinding binding) {
this.binding = binding;
}
@Override
public void setEndpoint(WSEndpoint endpoint) {
this.endpoint = endpoint;
endpoint.getComponentRegistry().add(this);
}
@Override
public Codec copy() {
return new XXXCodec(this);
}
@Override
public void decode(InputStream input, String contentType, Packet response)
throws IOException {
Message message = Messages.createEmpty(SOAPVersion.SOAP_11);
// TODO write logic to read input
stream and create Message object and set it in
packet.
response.setMessage(message);
}
@Override
public void decode(ReadableByteChannel arg0, String arg1, Packet arg2) {
throw new
UnsupportedOperationException();
}
@Override
public ContentType encode(Packet packet, OutputStream out)throws IOException {
Message message = packet.getMessage();
if (message != null) {
// TODO write logic to serialize message.
out.write("My XXX Decoder not implement yet".getBytes());
}
return xxxContentType;
}
@Override
public ContentType encode(Packet arg0, WritableByteChannel arg1) {
throw new UnsupportedOperationException();
}
@Override
public String getMimeType() {
return XXXContentType.XXX_CONTENT_TYPE;
}
@Override
public ContentType getStaticContentType(Packet arg0) {
return xxxContentType;
}
@Override
public T getSPI(Class arg0) {
// TODO Auto-generated method stub
return null;
}
}
Step 4: Create XXXBindingID.
Now its time to define ID for your codec. This id is used while defining endpoint. This ID can be any string. Normaly its URI. like
http://www.mycompany.com/codec/xxx/Create a class XXXBindingID extends com.sun.xml.ws.api.BindingID, and overwrite/implement methods.
Step 5: Create BindingIDFactory.
Add the defined Id to the factory pattern. So that it can serve your codec using its ID.
Your factory class extends "com.sun.xml.ws.api.BindingIDFactory".
Create your XXXBindingIDFactory class that extends form "com.sun.xml.ws.api.BindingIDFactory"
Step 6: Create services folder and BindingIDFactoy id file.
Now its time to pack XXX codec.
JAX-WS uses all bindingID factory declared in file "com.sun.xml.ws.api.BindingIDFactory" located inside "META-INF/services" folder.
Create "services" folder inside META-INF and create a file "com.sun.xml.ws.api.BindingIDFactory" (all dots are also part of file name), inside a file declare your XXXBindingIDFactory class.
Step 7: Create JAR.
Now select src folder and export as jar. Optionaly your may write ant script or other tools to create jar. Make sure META-INF folder included in jar with services folder.
After creating jar your custom Codec ready to use.
Step 8: Create testing WebService implementation class.
Now to test your Codec , create new Webproject and place the Codec jar inside WEB-INF/lib. and create your service implementation class.
For more about creating this test project for JAX-WS look at samples provided with Webservice developers pack. Or look in to attached sources.
Step 9: Create entry in sun-jaxws.xml.
define jax-ws endpoint with binding id.
<endpoint
name="XXXCodecTest"
implementation="com.test.codec.TestServiceImpl"
url-pattern="/xxx/ping"
binding="http://www.mycompany.com/codec/xxx/"/>
</endpoints>
Step 10: Test
Use your favorite tool and send post data with content type as "application/XXX"
Endpoint URL : http://localhost:8080/CustomCodecTest/xxx/ping
http://pluginsdemo.googlepages.com/CustomCodec.zip
(Note: this zip didn't include webservices-rt-1.3-SNAPSHOT.jar due to size, you can download and include it in your project)
-Sundar
-sundaramurthis@gmail.com