/* /*
/*

Class: PscObjectIDHandler

/*
*/ import java.util.*; import javax.xml.rpc.*; import javax.xml.soap.*; import javax.xml.rpc.handler.*; import javax.xml.rpc.handler.HandlerInfo; import javax.xml.rpc.handler.soap.*; import javax.xml.namespace.QName; /** * PscObjectIDHandler is a helper class for the JAX-RPC based clients such as * those provided by Axis and Sun. It enables you to work with the SOAP Headers * sent and received from the OpenEdge Web Services Adapter (WSA). When you use * the WSA to access a Web Service that is based on a Progress application * running in Session-Managed mode, the WSA will return an Object-ID in the * SOAP header of a connect message. This Object-ID header then needs to be * inserted in all subsequent SOAP messages that execute methods on that object. *

* To use this class: *

*

    *
  1. * Generate the client stubs from the Web Service's WSDL document obtained from * the Web Services Adapter. *
  2. * In your application, use the object's Service-Locator class to generate a * Service object. *
  3. * Create a String array for each handler you are creating that will hold the * names of the Progress proxy objects the handler will process. The WSDL * document has one PortType per Progress proxy object. *
  4. * Create a HandlerControlBlock variable for each Progress proxy object. *
  5. * For each port type, register a handler that will intercept, record, and send * the Progress proxy object ID. *
  6. * Use the Service object to obtain the Object's Port (Stub) objects. Each * Port type will correspond to exactly one Progress proxy object. *
  7. * When creating a new Progress proxy object from either a proxy AppObject or * proxy SubAppObject, the proxy object ID is returned from the Web Services * Adapter and stored in the current object's handler. Export the new object ID * from the current proxy object's HandlerControlBlock and import it into the * HandlerControlBlock that corresponds to the proxy object just created. *
*/ public class PscObjectIDHandler extends javax.xml.rpc.handler.GenericHandler { protected Map m_controlBlock = null; protected boolean m_debug = false; /** * *

The default class constructor. *

*/ public PscObjectIDHandler() { } /** * *

Create a ControlBlock object to interface the client application to * the PscObjectIDHandler object. *

*
* @param objectNames is an array of Strings that hold the proxy object * names the handler will handle. *
* @return ControlBlock */ public HandlerControlBlock createControlBlock(String[] objectNames) { return(new HandlerControlBlock(objectNames)); } /** * *

Setup all of the informaiton to register an instance of this class * as a SOAP message handler, then register it with the specified service. *

*
* @param service is the Service object to add the handler to * @param objName is a String array holding the PSC Object Names. It will * cause the handler to look for in the SOAP response Header elements for * one of the names that conform to objName + "ID" * @param targetURI is optional and can be used to specify the target URI * of the Web Service This and the portName make up the key to finding this * particular handler instance for a given PSC object * @param portName is the port name associated with the PSC object in the * client stubs. This and the targetURI make up the key to finding this * particular handler instance for a given PSC object * @param debug is a boolean that indicates that debug messages should * be output to stdout *
* @return HandlerControlBlock containing the information used and returned by the * handler *
* @exception Exception * @exception NullPointerException */ public static HandlerControlBlock registerObjectIDHandler(Service service, String[] pscObjName, String targetURI, String portName, boolean setDebug) throws Exception { // Ensure that the required basics are there. // if (null == service) { throw new NullPointerException("Cannot install a handler into a null service"); } if (null == pscObjName) { throw new NullPointerException("Cannot install a handler with a null list of object names"); } if (null == portName) { throw new NullPointerException("Cannot install a handler without an Port Name."); } // Create the handler configuration object and populate it with the // XxxxxHolder classes. The holder classes allow single object references // to be maintained and yet allow the client application to change // the values at will. // String[] idNames = new String[pscObjName.length]; // Prebuild the object names with the ID postfix. It will save a lot // of overhead when checking many times. // for (int i = 0; i < pscObjName.length; i++) { idNames[i] = new String(pscObjName[i] + "ID"); } // The target URI may be blank, but non-null. // String nameSpaceUri = ""; String delim = ""; if (null != targetURI && 0 < targetURI.length()) { nameSpaceUri = targetURI; if (targetURI.startsWith("urn:")) { delim = ":"; } else { delim = "/"; } } // Next, build the list of "mustUnderstand" headers that this // handler will process. // QName[] mustHandle = new QName[pscObjName.length]; for (int i = 0; i < pscObjName.length; i++ ) { String uri = nameSpaceUri + delim + pscObjName[i]; mustHandle[i] = new QName(uri, idNames[i]); } // Create a new control block with a blank list of object ids. // PscObjectIDHandler ttt = new PscObjectIDHandler(); HandlerControlBlock handlerConfig = ttt.createControlBlock(idNames); ttt = null; if (setDebug) { handlerConfig.put(HandlerControlBlock.DEBUG, ""); } // Now generate the port name for the handler. The port name is used // to select which handler chain to use when processing a request. A // service may have more than one handler chain, identified by the // QName of the target URI and port names. // QName portQName = new javax.xml.namespace.QName(nameSpaceUri, portName); handlerConfig.put(HandlerControlBlock.PORT_NAME, portQName.toString()); // Now get the service's handler chain storage and add a new instance // of this class to it. // List hChain = service.getHandlerRegistry().getHandlerChain(portQName); hChain.add(new javax.xml.rpc.handler.HandlerInfo(PscObjectIDHandler.class, handlerConfig, mustHandle)); // Return the ObjectHolder that can be used for this handler. // return(handlerConfig); } /** * *

Required by the Handler abstract class. See Handler documentation * for usage. *

*
* @return QName[] */ public QName[] getHeaders() { QName[] returnValue = new QName[] {}; return(returnValue); } /** * *

Save the handler configuration data for this instance. An instance * is generated for each output SOAP request and each input SOAP response. *

*
* @param */ public void init(HandlerInfo config) { if (null != config) { m_controlBlock = config.getHandlerConfig(); } } /** * *

Check the SOAP response message for the presence of an object ID * issued by the WSA to all new web service applicaiton objects. If the * name of the object to check for is null, the client is signalling us * to not perform any checking. If checking is turned on, and a match is * found, then we'll overwrite any exisiting information with what we find. *

*
* @param context is a MessageContext object holding the incoming message * information *
* @return boolean true if response processing is to continue or false if * it must be aborted */ public boolean handleResponse( MessageContext context ) { boolean returnValue = true; // Set the debug option state... // if (null != m_controlBlock && null != m_controlBlock.get(HandlerControlBlock.DEBUG)) { m_debug = true; } // Get the list of recorded object ids. // String portName = (String)m_controlBlock.get(HandlerControlBlock.PORT_NAME); Hashtable objectIds = (Hashtable)m_controlBlock.get(HandlerControlBlock.REQUEST_ID_STORE); // Set the array of SOAP header element [local] names to match on. // They should be the object name + "ID". // String[] objNames = (String[])m_controlBlock.get(HandlerControlBlock.OBJECT_IDS); // Make sure we don't trip on a missing reference. // if (null == objNames) { if (m_debug) { System.out.println("PscObjectIDHandler: (debug) No object names to search for in port " + portName + ". No seach performed."); } objNames = new String[] {}; } // Now process the response message... // Get the SOAP envelope, extract the Headers, then scan the // headers for a match. // try { SOAPMessageContext SMcontext =(SOAPMessageContext) context; SOAPMessage message = SMcontext.getMessage(); SOAPPart sp = message.getSOAPPart(); SOAPEnvelope sEnv = sp.getEnvelope(); // remove any previous last-response data. // m_controlBlock.remove(HandlerControlBlock.RESPONSE_ID_ELEMENT); m_controlBlock.remove(HandlerControlBlock.RESPONSE_ID_NAME); // Now if we've got the envelope to start with... // if (null != sEnv) { SOAPHeader sh = sEnv.getHeader(); if (sh != null) { Iterator headers = null; // First get the list of all SOAPHeaderElements from // the total list of XML elements contained in the Headers // section. // Iterator elements = sh.getChildElements(); java.util.List candidates = new ArrayList(); while (elements.hasNext()) { Object o = elements.next(); if (o instanceof SOAPHeaderElement) { SOAPHeaderElement e = (SOAPHeaderElement) o; candidates.add(e); } } headers = candidates.listIterator(); // Now sift through all the SOAP headers looking for // the one that matches our object id name format. // if (null != headers) { SOAPHeaderElement header; int index = 0; boolean foundHeader = false; while (headers.hasNext()) { header = (SOAPHeaderElement)headers.next(); String elementName = header.getElementName().getLocalName(); if (m_debug) { System.out.println("PscObjectIDHandler: (debug) Comparing " + elementName + " for port " + portName); } // Scroll through all the proxy object names registered // in the handler looking for a match on the object ID // name contained in the header element. // for (index = 0; index < objNames.length; index++) { if (elementName.equals(objNames[index])) { if (m_debug) { System.out.println("PscObjectIDHandler: (debug) Found " + "object " + elementName + " for port " + portName); } // Store the object's name if it hasn't been // stored before. if (null == objectIds.get(elementName)) { if (m_debug) { System.out.println("PscObjectIDHandler: (debug) " + "Storing object " + elementName + " for port " + portName); } objectIds.put(elementName , header); // If an proxy object name is not // registered to send with the next // request on this port (handler), use // the one just returned. // if (null == m_controlBlock.get(HandlerControlBlock.REQUEST_ID_NAME)) { m_controlBlock.put(HandlerControlBlock.REQUEST_ID_NAME, elementName); } } // Store the input from the last response. // m_controlBlock.put(HandlerControlBlock.RESPONSE_ID_ELEMENT ,header); m_controlBlock.put(HandlerControlBlock.RESPONSE_ID_NAME ,elementName); foundHeader = true; break; } } if (foundHeader) { break; } } } } } } catch (Exception e) { if (m_debug) { System.out.println("PscObjectIDHandler: (exception)" + e.toString()); } } return(returnValue); } /** * *

Handle the outgoing SOAP request. If an object ID is present, stick * it verbatim into the SOAP Header for the WSA to interpret and use. *

*
* @param context is a MessageContext object holding the incoming message * information *
* @return boolean true if response processing is to continue or false if * it must be aborted */ public boolean handleRequest( MessageContext context ) { boolean returnValue = true; // Set the debug option state... // if (null != m_controlBlock && null != m_controlBlock.get(HandlerControlBlock.DEBUG)) { m_debug = true; } // Now process the request message... // Get the SOAP message's envelope and then add the header element to // it. // try { String portName = (String) m_controlBlock.get(HandlerControlBlock.PORT_NAME); SOAPMessageContext SMcontext =(SOAPMessageContext) context; SOAPMessage message = SMcontext.getMessage(); SOAPPart sp = message.getSOAPPart(); SOAPEnvelope sEnv = sp.getEnvelope(); // Get the list of recorded object ids. // Hashtable objectIds = (Hashtable)m_controlBlock.get(HandlerControlBlock.REQUEST_ID_STORE); // Get the object id to send. // String objectIdName = (String)m_controlBlock.get(HandlerControlBlock.REQUEST_ID_NAME); if (null != sEnv) { // If none is defined, nothing to insert // if (null == objectIdName) { if (m_debug) { System.out.println("PscObjectIDHandler: (debug) No object name specified " + "for port " + portName + ". No Object ID inserted."); } } else { // Now get the object ID header element to send. // SOAPHeaderElement objectID = (SOAPHeaderElement)objectIds.get(objectIdName); if (null == objectID) { if (m_debug) { System.out.println("PscObjectIDHandler: (debug) No Object ID " + "for port " + portName + ". No Object ID inserted"); } } else { // Now contruct a new Header with the header element // to put into this request. // SOAPHeader sh = sEnv.getHeader(); if (sh == null) sh = sEnv.addHeader(); SOAPHeaderElement pscHeader = (SOAPHeaderElement)objectID; SOAPHeaderElement header = sh.addHeaderElement(pscHeader.getElementName()); Iterator uuid = pscHeader.getChildElements(); if (uuid.hasNext()) header.addChildElement((SOAPElement)uuid.next()); if (m_debug) { System.out.println("PscObjectIDHandler: (debug) Inserting " + objectIdName + " for port " + portName + "."); } } } } } catch (Exception e) { if (m_debug) { System.out.println("PscObjectIDHandler: (exception)" + e.toString()); } } return(returnValue); } /* * PROTECTED (SUPER) METHODS: */ /* * PRIVATE METHODS: */ }