The 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.
A handler is a special piece that conceptually sits between the client or server and the transport layer. A handler gets a chance to do something to the message right before or right after the message is put on the wire. Handlers can manipulate all aspects of SOAP messages using the SAAJ API. The picture below illustrates the concept of handlers.
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.
Below is the WSDL for the service.
<?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>
The WSDL defines an operation called EchoFile
which has a base64Binary
parameter as input and a base64Binary as output.
The ZipFileClientHandler
class is a JAX-RPC handler. It implements
the javax.xml.rpc.Handler
interface. When a client invokes an
operation, the handleRequest
method is called by the runtime to
process the 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 received, the WSSDK runtime invokes the
handleResponse
method of the handler, which then processes the
response. Finally, the values of the output parameters are returned to the client.
The ZipFileClientHandler
class compresses the file being sent out
using GZIPOutputStream
in the handleRequest
method
and it decompresses the echoed value using GZIPInputStream
.
The Base64Encoded
class is a utility class provided by the Novell exteNd WSSDK
for converting a BASE64 encoded byte array into a string and vice versa. Please note
that the handleRequest
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; } }
The ZipFileServerHandler
is a message handler for the server-side.
It is derived from ZipFileClientHandler
and does the 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); } }
The client gets access to the service using the JNDI lookup. It registers the
ZipFileHandler
into the registry for the port the client needs to access.
Then it reads a file and calls the EchoFile
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); } }
The FileTransferService
instantiates the ZipFileImpl
class and sets it as the target. In the init
method it registers the
ZipFileHandler
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.war
The ZipFile service implementation is shown below:
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()); | } } }
Please refer to the handler API documentation for more information. For detailed information about building, deploying and running the example refer to the README.
Copyright © 2003, 2004 Novell, Inc. All rights reserved. Copyright © 2001, 2002, 2003 SilverStream Software, LLC. All rights reserved.