Read on - design issue at the end. I have modified the original soap:header support implementation to allow full flexibility around the header management. The way I have achieve this is by allowing the user to specify the header object lifecycle. The current three lifecycles are:
HeaderLifeCycle.REPLACE: the response's header object will overwrite the request's one HeaderLifeCycle.DISCARD: the request's header object is removed from the list after the call. HeaderLifeCycle.PERSIST: the request's header stays as is. A user then do: binding.setHeader("CAM", cam, HeaderLifeCycle.REPLACE ); binding.setHeader("hdrSession", hdrs, HeaderLifeCycle.DISCARD ); To allow the setHeader() and getHeader() method to work off the binding (PortType) class I had to add a new extension to the PortType interface (currently org.apache.axis.client.HeaderSupport) this is all fine for client side since the HeaderSupport interface is implemented by the abstract Stub, but doing so, I broke the Impl class since it also implements the PortType. This being said we will ultimately want access to those two methods on the server-side but in the mean time (since I am not implementing server support now) I need a spot to put those two methods. Any idea? Would bringing back the skeleton be the answer to my problem? I am attaching the patch and the new files so you can experiment the problem with the Impl class. Note: I did not yet rename the Header and Headers classes as was suggested when I submitted the first implementation of the feature. All feedback much appreciated. -- Sylvain This message may contain privileged and/or confidential information. If you have received this e-mail in error or are not the intended recipient, you may not use, copy, disseminate or distribute it; do not open any attachments, delete it immediately from your system and notify the sender promptly by e-mail that you have done so. Thank you.
ServiceContext.java
Description: Binary data
HeaderLifeCycle.java
Description: Binary data
HeaderKey.java
Description: Binary data
HeaderSupport.java
Description: Binary data
Headers.java
Description: Binary data
Header.java
Description: Binary data
Index: xml-axis/java/src/org/apache/axis/client/Stub.java =================================================================== RCS file: /home/cvspublic/xml-axis/java/src/org/apache/axis/client/Stub.java,v retrieving revision 1.8 diff -r1.8 Stub.java 66a67,68 > import org.apache.axis.serviceContext.*; > import org.apache.axis.message.SOAPHeaderElement; 74c76 < public abstract class Stub implements javax.xml.rpc.Stub { --- > public abstract class Stub implements javax.xml.rpc.Stub, >org.apache.axis.client.HeaderSupport { 92a95,97 > // Support for Header > private ServiceContext serviceContext = new ServiceContext(); > 258a264,374 > > > /** > * This method returns the ServiceContext object for this binding. > * @return ServiceContext > */ > public ServiceContext getServiceContext() { > return serviceContext; > } > > /** > * This method allow the user to substitute this ServiceContext object with >another one. > * In general this is not required, but is provided in case someone would have >two binding to the same service > * and would want to have both binding using the same ServiceContext. > * @return ServiceContext > */ > public void setServiceContext(ServiceContext sc) { > serviceContext = sc; > } > > > /** > * This method allows a service consumer to set a SOAP Header object defined by > * <b>soap:header</b> operation element. Every opertaion refering to this >soap:header > * part in their binding will send this object as a SOAP Header. The returned >object > * will overwrite the current Service's ServiceContext instance of this part >object if > * replace is set to true. > * @param partName a String that identify the soap:header part > * @param header an Object that will be sent as a SOAPHeader > * @param lifeCycle a HeaderLifeCycle that defines the request's object life >cycle. > * @return void > */ > public void setHeader(String partName, Object header, HeaderLifeCycle lifeCycle) >{ > // Store the roudtrip attribute for this header, > HeaderKey hk = new HeaderKey(partName); > hk.setLifeCycle(lifeCycle); > > serviceContext.setHeader(hk, header); > } > > /** > * This method is meant to be used by the service consumer to retreive a >Service's > * ServiceContext header object. It returns the current object stored for the >given part > * name from the response hash of headers. The object the one returned by the >service > * provider for that part. It is null when the header does not exists, which >means that it > * has not been returned bu the service provider. > * @param partName a String that identify the soap:header part > * @return Object > */ > public Object getHeader(String partName) { > return serviceContext.getHeader(partName); > } > > /** > * This method is meant to be used by the BindingStub to set the requested >request header onto > * the Call object just before the call gets invoked. > * @return SOAPHeaderElement > */ > public SOAPHeaderElement getHeader(String namespace, String partName) { > > return new SOAPHeaderElement( > namespace, > partName, > serviceContext.getRequestHeader( new HeaderKey(partName)) ); > } > > /** > * This method is provided with the soap:header part name and the namespace so >it can update the > * Header object stored in the Service's ServiceContext using the one retreived >in the response > * @return void > */ > public void updateHeader(org.apache.axis.client.Call call, String namespace, >String partName) { > > try { > org.apache.axis.Message response = >call.getMessageContext().getResponseMessage(); > org.apache.axis.message.SOAPEnvelope env = >response.getSOAPEnvelope(); > > if ( env != null ) { > SOAPHeaderElement header = env.getHeaderByName(namespace, partName, >true); > > if ( header != null ) { > > // Retrieve the object from the response > Object theHeader = header.getObjectValue(); > // Retrieve this header object LifeCycle in the hash of request >headers. > HeaderKey currentHeaderKey = >serviceContext.getRequestHeaderKey(new HeaderKey(partName)); > > if ( currentHeaderKey != null ) { > > if ( >currentHeaderKey.getLifeCycle().equals(HeaderLifeCycle.REPLACE) ) { > // If the header lifeCycle is set to >HeaderLifeCycle.REPLACE we replace the > // header object found for that part in the >ServiceContext requestHeader Hashtable. > serviceContext.setRequestHeader(currentHeaderKey, >theHeader); > > } else if ( >currentHeaderKey.getLifeCycle().equals(HeaderLifeCycle.DISCARD) ) { > // If the header lifeCycle is set to >HeaderLifeCycle.DISCARD we remove the > // header object found for that part in the >ServiceContext requestHeader Hashtable. > serviceContext.removeRequestHeader(currentHeaderKey); > > } else if ( >currentHeaderKey.getLifeCycle().equals(HeaderLifeCycle.PERSIST) ) { > // If the header lifeCycle is set to >HeaderLifeCycle.PERSIST we keep the the > // header object therefore we do nothing. > } > > // In all case the received header object is stored in the >ServiceContext's > // responseHeader Hashtable. This could be change to a >lazyer approach where > // we would store the object on demand only.... > serviceContext.setResponseHeader(currentHeaderKey, >theHeader); > } > } > } > } catch ( Exception e ) { /* Not really sure what to do with this... */ } > } Index: xml-axis/java/src/org/apache/axis/wsdl/toJava/JavaInterfaceWriter.java =================================================================== RCS file: /home/cvspublic/xml-axis/java/src/org/apache/axis/wsdl/toJava/JavaInterfaceWriter.java,v retrieving revision 1.6 diff -r1.6 JavaInterfaceWriter.java 115c115 < pw.println("public interface " + className + " extends java.rmi.Remote {"); --- > pw.println("public interface " + className + " extends java.rmi.Remote, >org.apache.axis.client.HeaderSupport {"); Index: xml-axis/java/src/org/apache/axis/wsdl/toJava/JavaStubWriter.java =================================================================== RCS file: /home/cvspublic/xml-axis/java/src/org/apache/axis/wsdl/toJava/JavaStubWriter.java,v retrieving revision 1.55 diff -r1.55 JavaStubWriter.java 70a71 > import javax.wsdl.extensions.soap.SOAPHeader; 73a75 > import java.util.Enumeration; 231a234 > 259a263 > 262c266 < if (obj instanceof SOAPBody) { --- > if ( obj instanceof SOAPBody) { 269d272 < break; 275a279,283 > > // Take care of this operation's >header management stuff. > Headers headers = new Headers(); > headers.prepareHeaders( operation ); > 285c293 < operation, parameters, soapAction, namespace, isRPC); --- > operation, headers, parameters, soapAction, namespace, >isRPC); 468a477 > Headers headers, 578a588,595 > // Set the headers > pw.println(); > Enumeration headersEnum = headers.getRequestHeaders().elements(); > while ( headersEnum.hasMoreElements() ) { > Header h = (Header)headersEnum.nextElement(); > pw.println(" call.addHeader( getHeader( \"" + namespace + "\", >\"" + h.getPartName() + "\"));"); > } > 606a624,632 > > // Update the headers > headersEnum = headers.getResponseHeaders().elements(); > while ( headersEnum.hasMoreElements() ) { > Header h = (Header)headersEnum.nextElement(); > pw.println(" updateHeader( call, \"" + namespace + "\", \"" + >h.getPartName() + "\");"); > } > > pw.println();