Novell exteNd WSSDK supports the JAX-RPC APIs from Sun Microsystems. One of the JAX-RPC APIs is the SOAP Message Handler API. This API can be used for Encryption and Decryption, Authentication, Authorization, Logging, Auditing, etc.This example illustrates how to write a Message Handler, which can compress a file that is being sent as part of the SOAP message. This Web Service simply echoes a file, which gets compressed on the wire.
1 WSDL for FileTransferService
Below is the WSDL for the service.The wsdl defines an operation called EchoFile which has a base64Binary parameter as input and a base64Binary as output.<?xml version="1.0" encoding="utf-8"?> <definitions xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" targetNamespace="http://localhost/zipservice/" > <message name="EchoFileSoapIn"> <part name="parameter_in" type="xsd:base64Binary"/> </message> <message name="EchoFileSoapOut"> <part name="parameter_out" type="xsd:base64Binary"/> </message> <portType name="ZipFileSoap"> <operation name="EchoFile"> <input message="EchoFileSoapIn"/> <output message="EchoFileSoapOut"/> </operation> </portType> <binding name="ZipFileSoapBinding" type="ZipFileSoap"> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc"/> <operation name="EchoFile"> <soap:operation soapAction="http://localhost/zipservice/EchoFile" style="rpc"/> <input> <soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> </input> <output> <soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> </output> </operation> </binding> <service name="ZipFileService"> <port binding="ZipFileSoapBinding" name="ZipFileSoapPort"> <soap:address location="http://localhost:8080/services/zipfile"/> </port> </service> </definitions>2 The Message Handlers
TheZipFileClientHandler
class is a JAX-RPC handler. It implements thejavax.xml.rpc.Handler
interface. When a client invokes an operation, thehandleRequest
method is called by the runtime to process client request soap message. Once the message is processed by the handler, the request is sent to the server.When the response from the server is recieved, runtime invokes the
handleResponse
method of the handler, which then processes the response and then the values of the output parameters are returned to the client. TheZipFileClientHandler
class compresses the file being sent out as byte[] usingGZIPOutputStream
in thehandleRequest
method and it decompresses the echoed value usingGZIPInputStream
.The
Base64Encoded
class is a utility class provided by Novell exteNd WSSDK for converting byte[] into String and vice versa using base64 encoding. Please note that thehandleRequest
method of the client handler prints the compressed message to the console, which means that this will show as output when you run the client application.package handler; import java.io.*; import java.util.*; import java.util.zip.*; import javax.xml.soap.*; import javax.xml.rpc.handler.*; import javax.xml.rpc.handler.soap.*; import com.sssw.jbroker.web.ServiceException; import com.sssw.jbroker.util.Base64Encoder; public class ZipFileClientHandler implements Handler { public boolean handleRequest(MessageContext context) { | try | { | | SOAPMessageContext smc = (SOAPMessageContext)context; | | SOAPMessage msg = smc.getMessage(); | | SOAPPart sp = msg.getSOAPPart(); | | SOAPEnvelope se = sp.getEnvelope(); | | | | // next step based on the processing model for this handler | | SOAPBody body = se.getBody(); | | Iterator it = body.getChildElements(); | | SOAPElement opElem = (SOAPElement) it.next(); | | it = opElem.getChildElements(); | | SOAPElement pin = (SOAPElement) it.next(); | | it = pin.getChildElements(); | | Text textNode = (Text) it.next(); | | textNode.detachNode(); | | | | String encContent = textNode.getValue(); | | byte[] contentBytes = Base64Encoder.decode(encContent); | | | | // zip it | | ByteArrayOutputStream baos = new ByteArrayOutputStream(); | | GZIPOutputStream zos = new GZIPOutputStream(baos); | | zos.write(contentBytes); | | zos.flush(); | | zos.finish(); | | zos.close(); | | | | byte[] zippedbytes = baos.toByteArray(); | | | | String zippedContent = Base64Encoder.encode(zippedbytes); | | System.out.println("zipped-encoded content is:"); | | System.out.println(zippedContent); | | pin.addTextNode(zippedContent); | | msg.saveChanges(); | | return true; | } | catch(Throwable t) | { | | t.printStackTrace(); | | throw new ServiceException(t); | } } public boolean handleResponse(MessageContext context) { | try | { | | SOAPMessageContext smc = (SOAPMessageContext)context; | | SOAPMessage msg = smc.getMessage(); | | SOAPPart sp = msg.getSOAPPart(); | | SOAPEnvelope se = sp.getEnvelope(); | | | | // next step based on the processing model for this handler | | SOAPBody body = se.getBody(); | | Iterator it = body.getChildElements(); | | SOAPElement op = (SOAPElement) it.next(); | | SOAPElement param = (SOAPElement) op.getChildElements().next(); | | Text textNode = (Text) param.getChildElements().next(); | | String zippedenccontent = textNode.getValue(); | | System.out.println("zipped-encoded content is:"); | | System.out.println(zippedenccontent); | | textNode.detachNode(); | | | | byte[] zippedBytes = Base64Encoder.decode(zippedenccontent); | | | | ByteArrayInputStream bais = | | new ByteArrayInputStream(zippedBytes); | | GZIPInputStream zis = new GZIPInputStream(bais); | | ByteArrayOutputStream baos = new ByteArrayOutputStream(); | | int c = -1; | | while ((c = zis.read()) != -1) { | | | baos.write(c); | | } | | baos.flush(); | | byte[] contentBytes = baos.toByteArray(); | | | | String encContent = Base64Encoder.encode(contentBytes); | | param.addTextNode(encContent); | | msg.saveChanges(); | | return true; | } | catch(Throwable t) | { | | t.printStackTrace(); | | throw new ServiceException(t); | } } public boolean handleFault(MessageContext context) { return true; } // Lifecycle method public void init(HandlerInfo config) {} public void destroy() {} public javax.xml.namespace.QName[] getHeaders() { return null; } }
TheZipFileServerHandler
is a message handler for server-side. It is derived fromZipFileClientHandler
and does opposite to that of the client handler.package handler; import javax.xml.rpc.handler.*; public class ZipFileServerHandler extends ZipFileClientHandler { public boolean handleRequest(MessageContext context) { | return super.handleResponse(context); } public boolean handleResponse(MessageContext context) { | return super.handleRequest(context); } }3 The Client
The client gets access to the service using the JNDI lookup. It registers theZipFileHandler
into the registry for the port client needs to access. Then it reads a file and calls theEchoFile
method.package handler; import java.io.*; import java.util.*; import javax.xml.namespace.QName; import javax.xml.rpc.*; import javax.xml.rpc.handler.*; public class Client { public static void main(String[] args) throws Exception { | // instantiate the service. | ZipFileServiceImpl service = new ZipFileServiceImpl(); | | // set the handler chain | QName portName = new QName("http://localhost/zipservice/", | "ZipFileSoapPort"); | ArrayList handlers = new ArrayList(); | handlers.add(new HandlerInfo(ZipFileClientHandler.class, null, null)); | service.getHandlerRegistry().setHandlerChain(portName, handlers); | | // get access to the proxy | ZipFileSoap zipfile = service.getZipFileSoapPort(); | // set the end point address | ((Stub)zipfile)._setProperty("javax.xml.rpc.service.endpoint.address", | (args.length > 0) ? args[0] : "http://localhost:9090/zipfile"); | | | // get the content of file to be sent | String content = getContent("LICENSE.txt"); | byte[] contentBytes = content.getBytes(); | | // print the content to send | System.out.println("sending content:"); | System.out.println(content); | | // call echo file | byte[] echoedBytes = zipfile.echoFile(contentBytes); | | // print the content received | String result = new String(echoedBytes); | System.out.println("received content:"); | System.out.println(result); | | if(content.equals(result)) { | | System.out.println("echo file succedded!"); | } else { | | System.out.println("echo file failed!"); | } } private static String getContent(String fileName) throws IOException { | StringBuffer contentBuffer = new StringBuffer(); | FileInputStream fis = new FileInputStream(fileName); | int c = -1; | while((c = fis.read()) != -1) { | | contentBuffer.append((char) c); | } | fis.close(); | return new String(contentBuffer); } }4 ZipFile Web Service Implementation
TheFileTransferService
instantiates theZipFileImpl
class and sets it as the target. In theinit
method it registers theZipFileHandler
instance for the port for which the service is defined.As an example, if this server is deployed in the jwebserv Web Server, you have to start the Web Server like this:
jwebserv -verbose services.warThe ZipFile service implementation is shown below:Please refer to the JAX-RPC documentation from Sun Microsystems for more information.package handler; import java.util.ArrayList; import javax.servlet.ServletException; import javax.xml.namespace.QName; import javax.xml.rpc.handler.HandlerInfo; import javax.xml.rpc.handler.HandlerRegistry; import javax.xml.rpc.handler.HandlerChain; import com.sssw.jbroker.web.encoding.DefaultTypeMappingRegistry; public class FileTransferService extends ZipFileSoap_ServiceTieSkeleton { public FileTransferService() { | // initialize the delegate | setTarget(new ZipFileImpl()); } public void init() throws ServletException { | super.init(); | | try { | | // set the handler chain | | ArrayList handlers = new ArrayList(); | | handlers.add( | | new HandlerInfo(ZipFileServerHandler.class, null, null)); | | _setHandlerChain(handlers); | | | } catch (Throwable t) { | | t.printStackTrace(); | | throw new ServletException(t.getMessage()); | } } }
Copyright © 2000-2003, Novell, Inc. All rights reserved.