/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 2001 The Apache Software Foundation.  All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in
*    the documentation and/or other materials provided with the
*    distribution.
*
* 3. The end-user documentation included with the redistribution,
*    if any, must include the following acknowledgment:
*       "This product includes software developed by the
*        Apache Software Foundation (http://www.apache.org/)."
*    Alternately, this acknowledgment may appear in the software itself,
*    if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Axis" and "Apache Software Foundation" must
*    not be used to endorse or promote products derived from this
*    software without prior written permission. For written
*    permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
*    nor may "Apache" appear in their name, without prior written
*    permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation.  For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/

package org.apache.axis.serviceContext;

import java.io.Serializable;
import java.util.Hashtable;
import java.util.Enumeration;

/**
 * This class is providing what JAX-RPC calls the ServiceContext.  It is a 
 * datamember of the Stub class. It currently only provide encapsulation 
 * for two hashtables of header objects that are managed at the Service level 
 * through the Stub.
 * 
 * The BindingStub methods get the SOAP header objects from this hash and 
 * after the call to invoke the header objects are updated with the response object 
 * when the headers HeaderKey says so.
 * 
 * Note that the getHeader picks the header objects from the response hashtable while the 
 * setHeader pick them from the request hashtable.  [g|s]et[Response|Request]Header() methods 
 * are provided for more controll over the headers.
 * 
 * @author Sylvain St-Germain (sylvain@macadamian.com)
 */
public class ServiceContext{
  
	// Container of headers  
	private Hashtable requestHeaders  = null;
	private Hashtable responseHeaders = null;

	/**
	 * Construct a ServiceContext for this Binding Stub. Each binding has its own
	 * ServiceContext instance that manages the SOAPHeader.
	 */		
	public ServiceContext() {
	  requestHeaders  = new Hashtable();
	  responseHeaders = new Hashtable();
	}

	/**
	 * This method set a header in the requestHeaders hashtable.
	 * @param headerKey HeaderKey that uniquely identify a header object.
	 * @param headerValue Object that is sent in the request has a SOAPHeader
	 * @return void
	 */
	public void setHeader(HeaderKey headerKey, Object headerValue) {
	  setRequestHeader(headerKey, headerValue);
	}
	
	/**
	 * This method retreive a header in the responseHeaders hashtable.
	 * @param messageName String identify a soap:header message name attribute.
	 * @param partName String identify a soap:header part name attribute.
	 * @return Object
	 */
	public Object getHeader(String messageName, String partName) {
	  HeaderKey headerKey = new HeaderKey(messageName, partName);
		return getResponseHeader(headerKey);
	} 
	/**
	 * This method retreive a header in the responseHeaders hashtable.
	 * @param partName String identify a soap:header part name attribute.
	 * @return Object
	 */
	public Object getHeader(String partName) {
	  HeaderKey headerKey = new HeaderKey("", partName);
		return getResponseHeader(headerKey);	  
	} 

	/**
	 * Provided for consistency. @see setHeader()
	 * @param headerKey a HeaderKey header identificator
	 * @param headerValue Object that is sent in the request has a SOAPHeader
	 * @return void
	 */
	public void setRequestHeader(HeaderKey headerKey, Object headerValue) {
		requestHeaders.put(headerKey, headerValue);
	}
	
	/**
	 * Provided for consistency. @see setHeader()
	 * @param headerKey a HeaderKey header identificator
	 * @param headerValue Object that is sent in the request has a SOAPHeader
	 * @return void
	 */
	public void setResponseHeader(HeaderKey headerKey, Object headerValue) {
		responseHeaders.put(headerKey, headerValue);
	}

	/**
	 * This method is provided with a partial HeaderKey (no lifeCycle prop) and returns
	 * the stored copy of the headerKey from the request pool of headers.
	 * @param headerKey a HeaderKey that matches the one we are looking for.
	 * @return HeaderKey the matching headerKey.
	 */
	public HeaderKey getRequestHeaderKey( HeaderKey headerKey ) {
	    return getAHeaderKey(headerKey, getRequestHeaders());	    
	}
	
	/**
	 * This method is provided with a partial HeaderKey (no lifeCycle prop) and returns
	 * the stored copy of the headerKey from the response pool of headers.
	 * @param headerKey a HeaderKey that matches the one we are looking for.
	 * @return HeaderKey the matching headerKey.
	 */
	public HeaderKey getResponseHeaderKey( HeaderKey headerKey ) {
	    return getAHeaderKey(headerKey, getResponseHeaders());	    
	}

	/**
	 * Provided for consistency. @see getHeader()
	 * @param headerKey a HeaderKey header identificator
	 * @return void
	 */
	public Object getRequestHeader(HeaderKey headerKey) {   
		return getAHeader(headerKey, getRequestHeaders());
	}
	
	/**
	 * Provided for consistency. @see getHeader()
	 * @param headerKey a HeaderKey header identificator
	 * @return void
	 */
	public Object getResponseHeader(HeaderKey headerKey) {
		return getAHeader(headerKey, getResponseHeaders());
	}

	/**
	 * This method remove the requested requestHeaders from the requestHeaders hashtables.
	 * @return void
	 */
	public void removeRequestHeader(HeaderKey headerKey) {
	    requestHeaders.remove(headerKey);
	}

	/**
	 * This method clears both requestHeaders and responseHeaders hashtables.
	 * @return void
	 */
	public void clearHeaders() {
	  responseHeaders.clear();
	  requestHeaders.clear();
	}

  /**
   * Gets the requestHeaders.
   * @return Returns a Hashtable
   */
  public Hashtable getRequestHeaders() {
    return requestHeaders;
  }

  /**
   * Gets the responseHeaders.
   * @return Returns a Hashtable
   */
  public Hashtable getResponseHeaders() {
    return responseHeaders;
  }

	/**
	 * Returns the Object associated with the provided HeaderKey from the 
	 * appropriate hash of header
	 * @param headerKey a HeaderKey header identificator
	 * @param hash an Hashtable to look into for the headerKey header
	 */
	private Object getAHeader(HeaderKey headerKey, Hashtable hash) {

	  Enumeration e = hash.keys();	  	  
	  while ( e.hasMoreElements() ) {
	    HeaderKey thisHeader = (HeaderKey)e.nextElement();
	  	if ( thisHeader.equals(headerKey) )
	  		return hash.get(thisHeader);
	  }
	  
	  // The header may be absent, do not complain.	
	  return null;
	}

	/**
	 * Returns the stored HeaderKey from a provided HeaderKey.  The purpose
	 * of this method is to be able to retreive the HeaderLifeCycle attribute stored in 
	 * the HeaderKey for that HeaderKey marker.
	 * @param headerKey a HeaderKey header identificator
	 * @param hash an Hashtable to look into for the headerKey header
	 */
	private HeaderKey getAHeaderKey(HeaderKey headerKey, Hashtable hash) {

	  Enumeration e = hash.keys();	  	  
	  while ( e.hasMoreElements() ) {
	    HeaderKey thisHeader = (HeaderKey)e.nextElement();
	  	if ( thisHeader.equals(headerKey) )
	  		return thisHeader;
	  }
	  
	  // We did not find the stored headerKey for this header
	  return null;
	}

}
