/*
/*
/*
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:
*
*
* -
* Generate the client stubs from the Web Service's WSDL document obtained from
* the Web Services Adapter.
*
-
* In your application, use the object's Service-Locator class to generate a
* Service object.
*
-
* 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.
*
-
* Create a HandlerControlBlock variable for each Progress proxy object.
*
-
* For each port type, register a handler that will intercept, record, and send
* the Progress proxy object ID.
*
-
* Use the Service object to obtain the Object's Port (Stub) objects. Each
* Port type will correspond to exactly one Progress proxy object.
*
-
* 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:
*/
}