You are viewing a plain text version of this content. The canonical link for it is here.
Posted to java-dev@axis.apache.org by ro...@apache.org on 2001/06/14 09:04:18 UTC

cvs commit: xml-axis/java/test/session TestSimpleSession.java

robj        01/06/14 00:04:18

  Modified:    java/samples/bidbuy BidService.java
               java/src/org/apache/axis MessageContext.java AxisEngine.java
               java/src/org/apache/axis/client ServiceClient.java
               java/src/org/apache/axis/transport/http AxisServlet.java
                        HTTPConstants.java HTTPDispatchHandler.java
                        SimpleAxisServer.java AxisHttpSession.java
               java/src/org/apache/axis/providers/java JavaProvider.java
                        RPCProvider.java
               java/src/org/apache/axis/session Session.java
                        SimpleSession.java
               java/test/functional FunctionalTests.java
               java/test/session TestSimpleSession.java
  Added:       java/samples/addressbook Address.java AddressBook.java
                        AddressBook.wsdl AddressBookProxy.java deploy.xml
                        DOMUtils.java Main.java PhoneNumber.java testit.cmd
                        testit.sh
               java/test/functional TestAddressBookSample.java
  Log:
  Added first pass session support.
  - HTTPDispatchHandler extended to send & receive cookie headers.
  - ServiceClient's messageContext saves cookie values if any are placed there by HTTPDispatchHandler.
  - SimpleAxisServer keeps simple session table, and sends / receives rudimentary cookies.
  - JavaProvider looks in Session object to find service objects with session scope.
  - Address book sample (addressbook2) ported from Apache SOAP
  - Added functional test for address book sample
  Still to do:
  - example of application scope (blocked on some oddness deploying multiple services)
  - verify that this all works with AxisServlet
  - make client side clean up cookie state if session maintenance turned off in messageContext
  
  Revision  Changes    Path
  1.4       +1 -5      xml-axis/java/samples/bidbuy/BidService.java
  
  Index: BidService.java
  ===================================================================
  RCS file: /home/cvs/xml-axis/java/samples/bidbuy/BidService.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- BidService.java	2001/06/07 14:01:32	1.3
  +++ BidService.java	2001/06/14 07:03:54	1.4
  @@ -1,9 +1,5 @@
   package samples.bidbuy;
   
  -import org.apache.axis.utils.QName;
  -import org.apache.axis.encoding.BeanSerializer;
  -import org.apache.axis.encoding.TypeMappingRegistry;
  -
   /**
    * Big/PurchaseOrder Service
    */
  @@ -24,7 +20,7 @@
              return 0.8 * quantity;
           } else {
              return 0.7 * quantity;
  -        } 
  +        }
    
       }
   
  
  
  
  1.1                  xml-axis/java/samples/addressbook/Address.java
  
  Index: Address.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 2000 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 "SOAP" 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 and was
   * originally based on software copyright (c) 2000, International
   * Business Machines, Inc., http://www.apache.org.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  package samples.addressbook;
  
  /**
   * See \samples\addressbook\readme for info.
   *
   * @author Matthew J. Duftler (duftler@us.ibm.com)
   */
  public class Address
  {
      private int         streetNum;
      private String      streetName;
      private String      city;
      private String      state;
      private int         zip;
      private PhoneNumber phoneNumber;
      
      public Address()
      {
      }
      
      public Address(int streetNum, String streetName, String city, String state,
                     int zip, PhoneNumber phoneNumber)
      {
          this.streetNum = streetNum;
          this.streetName = streetName;
          this.city = city;
          this.state = state;
          this.zip = zip;
          this.phoneNumber = phoneNumber;
      }
      
      public void setStreetNum(int streetNum)
      {
          this.streetNum = streetNum;
      }
      
      public int getStreetNum()
      {
          return streetNum;
      }
      
      public void setStreetName(String streetName)
      {
          this.streetName = streetName;
      }
      
      public String getStreetName()
      {
          return streetName;
      }
      
      public void setCity(String city)
      {
          this.city = city;
      }
      
      public String getCity()
      {
          return city;
      }
      
      public void setState(String state)
      {
          this.state = state;
      }
      
      public String getState()
      {
          return state;
      }
      
      public void setZip(int zip)
      {
          this.zip = zip;
      }
      
      public int getZip()
      {
          return zip;
      }
      
      public void setPhoneNumber(PhoneNumber phoneNumber)
      {
          this.phoneNumber = phoneNumber;
      }
      
      public PhoneNumber getPhoneNumber()
      {
          return phoneNumber;
      }
      
      public String toString()
      {
          return streetNum + " " + streetName + "\n" +
              city + ", " + state + " " + zip + "\n" +
              phoneNumber;
      }
  }
  
  
  
  1.1                  xml-axis/java/samples/addressbook/AddressBook.java
  
  Index: AddressBook.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 2000 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 "SOAP" 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 and was
   * originally based on software copyright (c) 2000, International
   * Business Machines, Inc., http://www.apache.org.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  package samples.addressbook;
  
  import java.util.*;
  import org.w3c.dom.*;
  import javax.xml.parsers.*;
  //import org.apache.soap.util.xml.*;
  
  /**
   * See \samples\addressbook\readme for info.
   *
   * @author Matthew J. Duftler (duftler@us.ibm.com)
   */
  public class AddressBook
  {
      private Hashtable name2AddressTable = new Hashtable();
      
      public AddressBook()
      {
          addEntry("John B. Good",
                   new Address(123, "Main Street", "Anytown", "NY", 12345,
                               new PhoneNumber(123, "456", "7890")));
          addEntry("Bob Q. Public",
                   new Address(456, "North Whatever", "Notown", "ME", 12424,
                               new PhoneNumber(987, "444", "5566")));
      }
      
      public void addEntry(String name, Address address)
      {
          name2AddressTable.put(name, address);
      }
      
      public Address getAddressFromName(String name)
          throws IllegalArgumentException
      {
          if (name == null)
          {
              throw new IllegalArgumentException("The name argument must not be " +
                                                     "null.");
          }
          
          return (Address)name2AddressTable.get(name);
      }
      
      public Element getAllListings()
      {
          // RobJ not quite sure of the deal here...
          DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
          DocumentBuilder db;
          try {
              db  = dbf.newDocumentBuilder();
          } catch (ParserConfigurationException ex) {
              // RobJ does not know what to do in this case...
              throw new IllegalArgumentException("Parser configuration exception setting up documentBuilder: "+ex);
          }
          
          Document doc = db.newDocument();
          Element bookEl = doc.createElement("AddressBook");
          
          bookEl.appendChild(doc.createTextNode("\n"));
          
          for (Enumeration keys = name2AddressTable.keys();
               keys.hasMoreElements();)
          {
              String name = (String)keys.nextElement();
              Address address = (Address)name2AddressTable.get(name);
              Element listingEl = doc.createElement("Listing");
              Element nameEl = doc.createElement("Name");
              nameEl.appendChild(doc.createTextNode(name));
              listingEl.appendChild(doc.createTextNode("\n    "));
              listingEl.appendChild(nameEl);
              listingEl.appendChild(doc.createTextNode("\n    "));
              Element addressEl = doc.createElement("Address");
              Element streetNumEl = doc.createElement("StreetNum");
              streetNumEl.appendChild(doc.createTextNode(address.getStreetNum() + ""));
              addressEl.appendChild(doc.createTextNode("\n      "));
              addressEl.appendChild(streetNumEl);
              addressEl.appendChild(doc.createTextNode("\n      "));
              Element streetNameEl = doc.createElement("StreetName");
              streetNameEl.appendChild(doc.createTextNode(address.getStreetName()));
              addressEl.appendChild(streetNameEl);
              addressEl.appendChild(doc.createTextNode("\n      "));
              Element cityEl = doc.createElement("City");
              cityEl.appendChild(doc.createTextNode(address.getCity()));
              addressEl.appendChild(cityEl);
              addressEl.appendChild(doc.createTextNode("\n      "));
              Element stateEl = doc.createElement("State");
              stateEl.appendChild(doc.createTextNode(address.getState()));
              addressEl.appendChild(stateEl);
              addressEl.appendChild(doc.createTextNode("\n      "));
              Element zipEl = doc.createElement("Zip");
              zipEl.appendChild(doc.createTextNode(address.getZip() + ""));
              addressEl.appendChild(zipEl);
              addressEl.appendChild(doc.createTextNode("\n      "));
              PhoneNumber phone = address.getPhoneNumber();
              Element phoneEl = doc.createElement("PhoneNumber");
              phoneEl.appendChild(doc.createTextNode("\n        "));
              Element areaCodeEl = doc.createElement("AreaCode");
              areaCodeEl.appendChild(doc.createTextNode(phone.getAreaCode() + ""));
              phoneEl.appendChild(areaCodeEl);
              phoneEl.appendChild(doc.createTextNode("\n        "));
              Element exchangeEl = doc.createElement("Exchange");
              exchangeEl.appendChild(doc.createTextNode(phone.getExchange()));
              phoneEl.appendChild(exchangeEl);
              phoneEl.appendChild(doc.createTextNode("\n        "));
              Element numberEl = doc.createElement("Number");
              numberEl.appendChild(doc.createTextNode(phone.getNumber()));
              phoneEl.appendChild(numberEl);
              phoneEl.appendChild(doc.createTextNode("\n      "));
              addressEl.appendChild(phoneEl);
              addressEl.appendChild(doc.createTextNode("\n    "));
              listingEl.appendChild(addressEl);
              listingEl.appendChild(doc.createTextNode("\n  "));
              bookEl.appendChild(doc.createTextNode("  "));
              bookEl.appendChild(listingEl);
              bookEl.appendChild(doc.createTextNode("\n"));
          }
          
          return bookEl;
      }
      
      public int putListings(Element el)
      {
          // ROBJ WARNING: IS THIS RIGHT???
          // previously was "DOMUtils.getFirstChildElement(el)"
          Element listingEl = (Element)el.getFirstChild();
          int count = 0;
          
          while (listingEl != null)
          {
              String name = null;
              int    streetNum = 0;
              String streetName = "";
              String city = "";
              String state = "";
              int    zip = 0;
              int    areaCode = 0;
              String exchange = "";
              String number = "";
              
              Element tempEl = (Element)listingEl.getFirstChild();
              
              while (tempEl != null)
              {
                  String tagName = tempEl.getTagName();
                  
                  if (tagName.equals("Name"))
                  {
                      name = DOMUtils.getChildCharacterData(tempEl);
                  }
                  else if (tagName.equals("Address"))
                  {
                      Element tempEl2 = DOMUtils.getFirstChildElement(tempEl);
                      
                      while (tempEl2 != null)
                      {
                          String tagName2 = tempEl2.getTagName();
                          String content2 = DOMUtils.getChildCharacterData(tempEl2);
                          
                          if (tagName2.equals("StreetNum"))
                          {
                              streetNum = Integer.parseInt(content2);
                          }
                          else if (tagName2.equals("StreetName"))
                          {
                              streetName = content2;
                          }
                          else if (tagName2.equals("City"))
                          {
                              city = content2;
                          }
                          else if (tagName2.equals("State"))
                          {
                              state = content2;
                          }
                          else if (tagName2.equals("Zip"))
                          {
                              zip = Integer.parseInt(content2);
                          }
                          else if (tagName2.equals("City"))
                          {
                              city = content2;
                          }
                          else if (tagName2.equals("PhoneNumber"))
                          {
                              Element tempEl3 = DOMUtils.getFirstChildElement(tempEl2);
                              
                              while (tempEl3 != null)
                              {
                                  String tagName3 = tempEl3.getTagName();
                                  String content3 = DOMUtils.getChildCharacterData(tempEl3);
                                  
                                  if (tagName3.equals("AreaCode"))
                                  {
                                      areaCode = Integer.parseInt(content3);
                                  }
                                  else if (tagName3.equals("Exchange"))
                                  {
                                      exchange = content3;
                                  }
                                  else if (tagName3.equals("Number"))
                                  {
                                      number = content3;
                                  }
                                  
                                  tempEl3 = DOMUtils.getNextSiblingElement(tempEl3);
                              }
                          }
                          
                          tempEl2 = DOMUtils.getNextSiblingElement(tempEl2);
                      }
                  }
                  
                  tempEl = DOMUtils.getNextSiblingElement(tempEl);
              }
              
              if (name != null)
              {
                  Address address = new Address(streetNum, streetName, city, state,
                                                zip, new PhoneNumber(areaCode,
                                                                     exchange,
                                                                     number));
                  
                  addEntry(name, address);
                  count++;
              }
              
              listingEl = DOMUtils.getNextSiblingElement(listingEl);
          }
          
          return count;
      }
  }
  
  
  
  1.1                  xml-axis/java/samples/addressbook/AddressBook.wsdl
  
  Index: AddressBook.wsdl
  ===================================================================
  <?xml version="1.0" ?>
  
  <definitions name="urn:AddressFetcher" 
               targetNamespace="urn:AddressFetcher2"
               xmlns:typens="urn:xml-soap-address-demo"
               xmlns:xsd="http://www.w3.org/1999/XMLSchema"
               xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
               xmlns="http://schemas.xmlsoap.org/wsdl/">
  
    <!-- type defs -->
    <types>
      <xsd:schema targetNamespace="urn:xml-soap-address-demo"
                  xmlns:xsd="http://www.w3.org/1999/XMLSchema">
        <xsd:complexType name="phone">
          <xsd:element name="areaCode" type="xsd:int"/>
          <xsd:element name="exchange" type="xsd:string"/>
          <xsd:element name="number" type="xsd:string"/>
        </xsd:complexType>
  
        <xsd:complexType name="address">
          <xsd:element name="streetNum" type="xsd:int"/>
          <xsd:element name="streetName" type="xsd:string"/>
          <xsd:element name="city" type="xsd:string"/>
          <xsd:element name="state" type="xsd:string"/>
          <xsd:element name="zip" type="xsd:int"/>
          <xsd:element name="phoneNumber" type="typens:phone"/>
        </xsd:complexType>
      </xsd:schema>
    </types>
  
    <!-- message declns -->
    <message name="AddEntryRequest">
      <part name="name" type="xsd:string"/>
      <part name="address" type="typens:address"/>
    </message>
  
    <message name="GetAddressFromNameRequest">
      <part name="name" type="xsd:string"/>
    </message>
  
    <message name="GetAddressFromNameResponse">
      <part name="address" type="typens:address"/>
    </message>
  
    <!-- port type declns -->
    <portType name="AddressBook">
      <operation name="addEntry">
        <input message="AddEntryRequest"/>
      </operation>
      <operation name="getAddressFromName">
        <input message="GetAddressFromNameRequest"/>
        <output message="GetAddressFromNameResponse"/>
      </operation>
    </portType>
  
    <!-- binding declns -->
    <binding name="AddressBookSOAPBinding" type="AddressBook">
      <soap:binding style="rpc" 
                    transport="http://schemas.xmlsoap.org/soap/http"/>
      <operation name="addEntry">
        <soap:operation soapAction=""/>
        <input>
          <soap:body use="encoded" 
                     namespace="urn:AddressFetcher2" 
                     encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
        </input>
        <output>
          <soap:body use="encoded" 
                     namespace="urn:AddressFetcher2"
                     encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
        </output>
      </operation>
      <operation name="getAddressFromName">
        <soap:operation soapAction=""/>
        <input>
          <soap:body use="encoded"
                     namespace="urn:AddressFetcher2"
                     encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
        </input>
        <output>
          <soap:body use="encoded" 
                     namespace="urn:AddressFetcher2"
                     encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
        </output>
      </operation>
    </binding>
  
    <!-- service decln -->
    <service name="AddressBookService">
      <port name="AddressBook" binding="AddressBookSOAPBinding">
        <soap:address location="http://localhost:2020/soap/servlet/rpcrouter"/>
      </port>
    </service>
  
  </definitions>
  
  
  
  1.1                  xml-axis/java/samples/addressbook/AddressBookProxy.java
  
  Index: AddressBookProxy.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 2000 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 "SOAP" 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 and was
   * originally based on software copyright (c) 2000, International
   * Business Machines, Inc., http://www.apache.org.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  package samples.addressbook;
  
  import java.net.*;
  import java.util.*;
  /*
   import org.apache.soap.*;
   import org.apache.soap.encoding.*;
   import org.apache.soap.rpc.*;
   import org.apache.soap.util.xml.*;
   import org.apache.soap.transport.*;
   */
  
  import org.apache.axis.AxisFault;
  import org.apache.axis.client.ServiceClient;
  import org.apache.axis.client.http.HTTPTransport;
  import org.apache.axis.encoding.BeanSerializer;
  import org.apache.axis.utils.QName ;
  
  /**
   * Proxy for the address book service described in the AddressBook.wsdl
   * file found in this directory.
   * Based loosely on Sanjiva's WSDL skeleton, but heavily updated
   * for Axis.
   *
   * @author Sanjiva Weerawarana <sa...@watson.ibm.com>
   */
  public class AddressBookProxy
  {
      private ServiceClient call = new ServiceClient(new HTTPTransport());
      private String service = "";
      
      public AddressBookProxy(String serviceName) throws MalformedURLException
      {
          service = serviceName;
          try {
              // register the PurchaseOrder class
              QName qn1 = new QName(serviceName, "Address");
              Class cls = Address.class;
              call.addSerializer(cls, qn1, new BeanSerializer(cls));
              call.addDeserializerFactory(qn1, cls, BeanSerializer.getFactory(cls));
              
              // register the PhoneNumber class
              QName qn2 = new QName(serviceName, "PhoneNumber");
              cls = PhoneNumber.class;
              call.addSerializer(cls, qn2, new BeanSerializer(cls));
              call.addDeserializerFactory(qn2, cls, BeanSerializer.getFactory(cls));
          } catch (Exception ex) {
              throw new IllegalArgumentException("Exception configurizing bean serialization: "+ex);
          }
          
          call.set(HTTPTransport.ACTION, serviceName);
      }
      
      public synchronized void setEndPoint(URL url)
      {
          call.set(HTTPTransport.URL, url.toString());
      }
      
      public synchronized void setMaintainSession (boolean session)
      {
          call.setMaintainSession(session);
      }
      
      
      public synchronized void addEntry(java.lang.String name,
                                        Address address) throws AxisFault
      {
          if (call.get(HTTPTransport.URL) == null)
          {
              throw new AxisFault(
                  "A URL must be specified via " +
                      "AddressBookProxy.setEndPoint(URL).");
          }
          
          Object resp = call.invoke(service, "addEntry",
                                    new Object[] {name, address});
          
          // Check the response.
          if (resp instanceof AxisFault)
          {
              throw (AxisFault)resp;
          }
      }
      
      public synchronized Address getAddressFromName
          (java.lang.String name) throws AxisFault
      {
          if (call.get(HTTPTransport.URL) == null)
          {
              throw new AxisFault(
                  "A URL must be specified via " +
                      "AddressBookProxy.setEndPoint(URL).");
          }
          
          Object resp = call.invoke(service, "getAddressFromName",
                                    new Object[] {name});
          /*
           System.out.print("Response is "+resp);
           if (resp != null) System.out.print(", class is "+resp.getClass().getName());
           System.out.println();
           */
          // Check the response.
          if (resp instanceof AxisFault)
          {
              throw (AxisFault)resp;
          }
          else
          {
              return (Address)resp;
          }
          
      }
      
  }
  
  
  
  1.1                  xml-axis/java/samples/addressbook/deploy.xml
  
  Index: deploy.xml
  ===================================================================
  <!-- Use this file to deploy some handlers/chains and services  -->
  <!-- Two ways to do this:                                       -->
  <!--   java org.apache.axis.utils.Admin deploy.xml              -->
  <!--      from the same dir that the Axis engine runs           -->
  <!-- or                                                         -->
  <!--   java org.apache.axis.client.AdminClient deploy.xml       -->
  <!--      after the axis server is running                      -->
  <!-- This file will be replaced by WSDD once it's ready         -->
  
  <deploy>
    <chain   name="book"     flow="RPCDispatcher" />
  
    <service name="urn:AddressFetcher2" pivot="book" >
      <option name="className" value="samples.addressbook.AddressBook" />
      <option name="methodName" value="addEntry getAddressFromName" />
      <option name="scope" value="Session" />
    </service>
  
    <bean xmlns:book2="urn:AddressFetcher2">
      <book2:Address       classname="samples.addressbook.Address"/>
      <book2:PhoneNumber      classname="samples.addressbook.PhoneNumber"/>
    </bean>
  
  <!--
  Commented out this test for now. This seems to conflict somehow with the first
  service definition... if you uncomment this service & bean definition,
  the functional test suddenly starts breaking!  Will look into this further...
  See commented-out code in Main.main() - RobJ
  -->
  
  <!--
    <service name="urn:AddressFetcher3" pivot="book" >
      <option name="className" value="samples.addressbook.AddressBook" />
      <option name="methodName" value="addEntry getAddressFromName" />
      <option name="scope" value="Application" />
    </service>
  
    <bean xmlns:book3="urn:AddressFetcher3">
      <book3:Address       classname="samples.addressbook.Address"/>
      <book3:PhoneNumber      classname="samples.addressbook.PhoneNumber"/>
    </bean>
  -->
  
  </deploy>
  
  
  
  1.1                  xml-axis/java/samples/addressbook/DOMUtils.java
  
  Index: DOMUtils.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 2000 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 "SOAP" 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 and was
   * originally based on software copyright (c) 2000, International
   * Business Machines, Inc., http://www.apache.org.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  package samples.addressbook;
  
  import org.w3c.dom.*;
  
  /**
   * @author Matthew J. Duftler
   * @author Sanjiva Weerawarana
   */
  public class DOMUtils {
      /**
       * The namespaceURI represented by the prefix <code>xmlns</code>.
       */
      private static String NS_URI_XMLNS = "http://www.w3.org/2000/xmlns/";
      
      /**
       * Returns the value of an attribute of an element. Returns null
       * if the attribute is not found (whereas Element.getAttribute
       * returns "" if an attrib is not found).
       *
       * @param el       Element whose attrib is looked for
       * @param attrName name of attribute to look for
       * @return the attribute value
       */
      static public String getAttribute (Element el, String attrName) {
          String sRet = null;
          Attr   attr = el.getAttributeNode(attrName);
          
          if (attr != null) {
              sRet = attr.getValue();
          }
          return sRet;
      }
      
      /**
       * Returns the value of an attribute of an element. Returns null
       * if the attribute is not found (whereas Element.getAttributeNS
       * returns "" if an attrib is not found).
       *
       * @param el       Element whose attrib is looked for
       * @param namespaceURI namespace URI of attribute to look for
       * @param localPart local part of attribute to look for
       * @return the attribute value
       */
      static public String getAttributeNS (Element el,
                                           String namespaceURI,
                                           String localPart) {
          String sRet = null;
          Attr   attr = el.getAttributeNodeNS (namespaceURI, localPart);
          
          if (attr != null) {
              sRet = attr.getValue ();
          }
          
          return sRet;
      }
      
      /**
       * Concat all the text and cdata node children of this elem and return
       * the resulting text.
       *
       * @param parentEl the element whose cdata/text node values are to
       *                 be combined.
       * @return the concatanated string.
       */
      static public String getChildCharacterData (Element parentEl) {
          if (parentEl == null) {
              return null;
          }
          Node          tempNode = parentEl.getFirstChild();
          StringBuffer  strBuf   = new StringBuffer();
          CharacterData charData;
          
          while (tempNode != null) {
              switch (tempNode.getNodeType()) {
                  case Node.TEXT_NODE :
                  case Node.CDATA_SECTION_NODE : charData = (CharacterData)tempNode;
                      strBuf.append(charData.getData());
                      break;
              }
              tempNode = tempNode.getNextSibling();
          }
          return strBuf.toString();
      }
      
      /**
       * Return the first child element of the given element. Null if no
       * children are found.
       *
       * @param elem Element whose child is to be returned
       * @return the first child element.
       */
      public static Element getFirstChildElement (Element elem) {
          for (Node n = elem.getFirstChild (); n != null; n = n.getNextSibling ()) {
              if (n.getNodeType () == Node.ELEMENT_NODE) {
                  return (Element) n;
              }
          }
          return null;
      }
      
      /**
       * Return the next sibling element of the given element. Null if no
       * more sibling elements are found.
       *
       * @param elem Element whose sibling element is to be returned
       * @return the next sibling element.
       */
      public static Element getNextSiblingElement (Element elem) {
          for (Node n = elem.getNextSibling (); n != null; n = n.getNextSibling ()) {
              if (n.getNodeType () == Node.ELEMENT_NODE) {
                  return (Element) n;
              }
          }
          return null;
      }
      
      /**
       * Return the first child element of the given element which has the
       * given attribute with the given value.
       *
       * @param elem      the element whose children are to be searched
       * @param attrName  the attrib that must be present
       * @param attrValue the desired value of the attribute
       *
       * @return the first matching child element.
       */
      public static Element findChildElementWithAttribute (Element elem,
                                                           String attrName,
                                                           String attrValue) {
          for (Node n = elem.getFirstChild (); n != null; n = n.getNextSibling ()) {
              if (n.getNodeType () == Node.ELEMENT_NODE) {
                  if (attrValue.equals (DOMUtils.getAttribute ((Element) n, attrName))) {
                      return (Element) n;
                  }
              }
          }
          return  null;
      }
      
      /**
       * Count number of children of a certain type of the given element.
       *
       * @param elem the element whose kids are to be counted
       *
       * @return the number of matching kids.
       */
      public static int countKids (Element elem, short nodeType) {
          int nkids = 0;
          for (Node n = elem.getFirstChild (); n != null; n = n.getNextSibling ()) {
              if (n.getNodeType () == nodeType) {
                  nkids++;
              }
          }
          return nkids;
      }
      
      /**
       * Given a prefix and a node, return the namespace URI that the prefix
       * has been associated with. This method is useful in resolving the
       * namespace URI of attribute values which are being interpreted as
       * QNames. If prefix is null, this method will return the default
       * namespace.
       *
       * @param context the starting node (looks up recursively from here)
       * @param prefix the prefix to find an xmlns:prefix=uri for
       *
       * @return the namespace URI or null if not found
       */
      public static String getNamespaceURIFromPrefix (Node context,
                                                      String prefix) {
          short nodeType = context.getNodeType ();
          Node tempNode = null;
          
          switch (nodeType)
          {
              case Node.ATTRIBUTE_NODE :
                  {
                      tempNode = ((Attr) context).getOwnerElement ();
                      break;
                  }
              case Node.ELEMENT_NODE :
                  {
                      tempNode = context;
                      break;
                  }
              default :
                  {
                      tempNode = context.getParentNode ();
                      break;
                  }
          }
          
          while (tempNode != null && tempNode.getNodeType () == Node.ELEMENT_NODE)
          {
              Element tempEl = (Element) tempNode;
              String namespaceURI = (prefix == null)
                  ? getAttribute (tempEl, "xmlns")
                  : getAttributeNS (tempEl, NS_URI_XMLNS, prefix);
              
              if (namespaceURI != null)
              {
                  return namespaceURI;
              }
              else
              {
                  tempNode = tempEl.getParentNode ();
              }
          }
          
          return null;
      }
      
      public static Element getElementByID(Element el, String id)
      {
          if (el == null)
              return null;
          String thisId = el.getAttribute("id");
          if (id.equals(thisId))
              return el;
          
          NodeList list = el.getChildNodes();
          for (int i = 0; i < list.getLength(); i++) {
              Node node = list.item(i);
              if (node instanceof Element) {
                  Element ret = getElementByID((Element)node, id);
                  if (ret != null)
                      return ret;
              }
          }
          
          return null;
      }
  }
  
  
  
  1.1                  xml-axis/java/samples/addressbook/Main.java
  
  Index: Main.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 2000 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 "SOAP" 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 and was
   * originally based on software copyright (c) 2000, International
   * Business Machines, Inc., http://www.apache.org.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  package samples.addressbook;
  
  import java.net.*;
  import org.apache.axis.client.ServiceClient;
  import org.apache.axis.client.http.HTTPTransport;
  import org.apache.axis.utils.Options;
  import org.apache.axis.utils.Debug;
  
  /**
   * This class shows how to use the ServiceClient's ability to
   * become session aware.
   *
   * @author Rob Jellinghaus (robj@unrealities.com)
   * @author Sanjiva Weerawarana <sa...@watson.ibm.com>
   */
  public class Main {
      static String name1 = "Purdue Boilermaker";
      static Address addr1 = new Address (1, "University Drive",
                                          "West Lafayette", "IN", 47907,
                                          new PhoneNumber (765, "494", "4900"));
      
      private static void printAddress (Address ad) {
          if (ad == null) {
              System.err.println ("\t[ADDRESS NOT FOUND!]");
              return;
          }
          System.err.println ("\t" + ad.getStreetNum() + " " +
                                  ad.getStreetName());
          System.err.println ("\t" + ad.getCity() + ", " + ad.getState() + " " +
                                  ad.getZip());
          PhoneNumber ph = ad.getPhoneNumber();
          System.err.println ("\tPhone: (" + ph.getAreaCode() + ") " +
                                  ph.getExchange() + "-" + ph.getNumber());
      }
      
      private static Object doit (AddressBookProxy ab) throws Exception {
          System.err.println (">> Storing address for '" + name1 + "'");
          ab.addEntry (name1, addr1);
          System.err.println (">> Querying address for '" + name1 + "'");
          Address resp = ab.getAddressFromName (name1);
          System.err.println (">> Response is:");
          printAddress (resp);
          
          // if we are NOT maintaining session, resp must be == null.
          // If we ARE, resp must be != null.
          
          System.err.println (">> Querying address for '" + name1 + "' again");
          resp = ab.getAddressFromName (name1);
          System.err.println (">> Response is:");
          printAddress (resp);
          return resp;
      }
      
      public static void main (String[] args) throws Exception {
          Options opts = new Options(args);
          Debug.setDebugLevel( opts.isFlagSet( 'd' ) );
          URL serviceURL = new URL(opts.getURL());
          
          System.err.println ("Using proxy without session maintenance.");
          AddressBookProxy ab1 = new AddressBookProxy ("urn:AddressFetcher2");
          if (serviceURL != null) {
              ab1.setEndPoint (serviceURL);
          }
          ab1.setMaintainSession (false);
          Object ret = doit (ab1);
          if (ret != null) {
              throw new Exception("non-session test expected null response, got "+ret);
          }
          
          System.err.println ("\n\nUsing proxy with session maintenance.");
          AddressBookProxy ab2 = new AddressBookProxy ("urn:AddressFetcher2");
          if (serviceURL != null) {
              ab2.setEndPoint (serviceURL);
          }
          ab2.setMaintainSession (true);
          ret = doit (ab2);
          if (ret == null) {
              throw new Exception("session test expected non-null response, got "+ret);
          }
          
          /* This code commented out for now.  This test relies on the currently-
           commented-out section of deploy.xml.  See that file for more.
           
           System.err.println ("Using application-scope proxy without session maintenance.");
           AddressBookProxy ab3 = new AddressBookProxy ("urn:AddressFetcher3");
           if (serviceURL != null) {
           ab3.setEndPoint (serviceURL);
           }
           ab3.setMaintainSession (false);
           ret = doit (ab3);
           if (ret == null) {
           throw new Exception("non-session test of app provider expected non-null response, got "+ret);
           }
           */
      }
  }
  
  
  
  1.1                  xml-axis/java/samples/addressbook/PhoneNumber.java
  
  Index: PhoneNumber.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 2000 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 "SOAP" 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 and was
   * originally based on software copyright (c) 2000, International
   * Business Machines, Inc., http://www.apache.org.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  package samples.addressbook;
  
  /**
   * See \samples\addressbook\readme for info.
   *
   * @author Matthew J. Duftler (duftler@us.ibm.com)
   */
  public class PhoneNumber
  {
      private int    areaCode;
      private String exchange;
      private String number;
      
      public PhoneNumber()
      {
      }
      
      public PhoneNumber(int areaCode, String exchange, String number)
      {
          this.areaCode = areaCode;
          this.exchange = exchange;
          this.number   = number;
      }
      
      public void setAreaCode(int areaCode)
      {
          this.areaCode = areaCode;
      }
      
      public int getAreaCode()
      {
          return areaCode;
      }
      
      public void setExchange(String exchange)
      {
          this.exchange = exchange;
      }
      
      public String getExchange()
      {
          return exchange;
      }
      
      public void setNumber(String number)
      {
          this.number = number;
      }
      
      public String getNumber()
      {
          return number;
      }
      
      public String toString()
      {
          return "(" + areaCode + ") " + exchange + "-" + number;
      }
  }
  
  
  
  1.1                  xml-axis/java/samples/addressbook/testit.cmd
  
  Index: testit.cmd
  ===================================================================
  @echo off
  echo This test assumes a server URL of http://localhost:8080/axis/servlet/
  echo Deploying the addressbook2 service...
  java org.apache.axis.client.http.AdminClient deploy.xml
  echo .
  echo Running demo...
  java samples.addressbook.Main
  
  
  
  1.1                  xml-axis/java/samples/addressbook/testit.sh
  
  Index: testit.sh
  ===================================================================
  echo This test assumes a server URL of http://localhost:8080/axis/servlet/
  echo Deploying the addressbook2 service...
  java org.apache.axis.client.http.AdminClient deploy.xml
  echo
  echo Running demo...
  java samples.addressbook.Main
  
  
  
  1.37      +22 -3     xml-axis/java/src/org/apache/axis/MessageContext.java
  
  Index: MessageContext.java
  ===================================================================
  RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/MessageContext.java,v
  retrieving revision 1.36
  retrieving revision 1.37
  diff -u -r1.36 -r1.37
  --- MessageContext.java	2001/06/13 21:07:37	1.36
  +++ MessageContext.java	2001/06/14 07:03:58	1.37
  @@ -123,6 +123,14 @@
        * A Session associated with this request.
        */
       private Session          session;
  +    
  +    /**
  +     * Should we track session state, or not?
  +     * default is not.
  +     * Could potentially refactor this so that
  +     * maintainSession iff session != null...
  +     */
  +    private boolean         maintainSession = false;
   
       /**
        *
  @@ -185,6 +193,20 @@
       {
           this.session = session;
       }
  +    
  +    /**
  +     * Set whether we are maintaining session state
  +     */
  +    public void setMaintainSession (boolean yesno) {
  +        maintainSession = yesno;
  +    }
  +    
  +    /**
  +     * Are we maintaining session state?
  +     */
  +    public boolean getMaintainSession () {
  +        return maintainSession;
  +    }
   
       /**
        * Placeholder.
  @@ -299,9 +321,6 @@
       /** Has a quit been requested? Hackish... but useful... -- RobJ */
       public static String QUIT_REQUESTED = "quit.requested";
     
  -    /** Property name for session context */
  -    public static String SESSION_CONTEXT = "session.context";
  -
       /** A String with the user's ID (if available)
        */
       public static String USERID              = "user.id";
  
  
  
  1.5       +23 -3     xml-axis/java/src/org/apache/axis/AxisEngine.java
  
  Index: AxisEngine.java
  ===================================================================
  RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/AxisEngine.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- AxisEngine.java	2001/06/13 21:08:30	1.4
  +++ AxisEngine.java	2001/06/14 07:03:59	1.5
  @@ -62,6 +62,8 @@
   import org.apache.axis.handlers.* ;
   import org.apache.axis.handlers.soap.* ;
   import org.apache.axis.registries.* ;
  +import org.apache.axis.session.Session;
  +import org.apache.axis.session.SimpleSession;
   import org.apache.axis.encoding.*;
   
   /**
  @@ -88,9 +90,17 @@
       protected Properties props = new Properties();
       
       /**
  +     * This engine's Session.  This Session supports "application scope"
  +     * in the Apache SOAP sense... if you have a service with "application
  +     * scope", have it store things in this Session.
  +     */
  +    private Session session = new SimpleSession();
  +    
  +    
  +    /**
        * No-arg constructor.  Loads properties from the "axis.properties"
        * file if it exists.
  -     * 
  +     *
        */
       public AxisEngine()
       {
  @@ -111,7 +121,7 @@
       /**
        * Allows the Listener to specify which handler/service registry
        * implementation they want to use.
  -     * 
  +     *
        * @param handlers the Handler registry.
        * @param services the Service registry.
        */
  @@ -126,7 +136,7 @@
   
       /**
        * Constructor specifying registry filenames.
  -     * 
  +     *
        * @param handlerRegFilename the name of the Handler registry file.
        * @param serviceRegFilename the name of the Service registry file.
        */
  @@ -273,5 +283,15 @@
       public void undeployService(String key)
       {
           getHandlerRegistry().remove(key);
  +	}
  +
  +    /**
  +     * accessor only, for application session
  +     * (could call it "engine session" instead, but named with reference
  +     * to Apache SOAP's notion of "application scope")
  +     */
  +    public Session getApplicationSession () {
  +        return session;
       }
  +
   };
  
  
  
  1.12      +10 -3     xml-axis/java/src/org/apache/axis/client/ServiceClient.java
  
  Index: ServiceClient.java
  ===================================================================
  RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/client/ServiceClient.java,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- ServiceClient.java	2001/06/13 17:53:25	1.11
  +++ ServiceClient.java	2001/06/14 07:04:02	1.12
  @@ -99,7 +99,7 @@
       public  boolean doLocal = false ;
       private static final boolean DEBUG_LOG = false;
       
  -    // Our AxisClien
  +    // Our AxisClient
       private AxisClient engine;
       
       // The description of our service
  @@ -182,6 +182,13 @@
       }
       
       /**
  +     * pass through whether we are maintaining session state
  +     */
  +    public void setMaintainSession (boolean yesno) {
  +        msgContext.setMaintainSession(yesno);
  +    }
  +    
  +    /**
        * all-purpose accessor for fringe cases....
        */
       public MessageContext getMessageContext () {
  @@ -300,8 +307,8 @@
           Debug.Print( 1, "Enter: ClientMessage::invoke(MessageContext)" );
           
           // If local is specified, override the transport handlers Once there
  -        // is a convenient way for the client to specify the transport 
  -        // handler, we might want to consider removing this code and doLocal 
  +        // is a convenient way for the client to specify the transport
  +        // handler, we might want to consider removing this code and doLocal
           // entirely.
           if (doLocal) {
               msgContext.setProperty(MessageContext.TRANS_INPUT, "LocalSender");
  
  
  
  1.24      +10 -6     xml-axis/java/src/org/apache/axis/transport/http/AxisServlet.java
  
  Index: AxisServlet.java
  ===================================================================
  RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/transport/http/AxisServlet.java,v
  retrieving revision 1.23
  retrieving revision 1.24
  diff -u -r1.23 -r1.24
  --- AxisServlet.java	2001/06/13 15:39:14	1.23
  +++ AxisServlet.java	2001/06/14 07:04:03	1.24
  @@ -2,7 +2,7 @@
    * The Apache Software License, Version 1.1
    *
    *
  - * Copyright (c) 2001 The Apache Software Foundation.  All rights 
  + * Copyright (c) 2001 The Apache Software Foundation.  All rights
    * reserved.
    *
    * Redistribution and use in source and binary forms, with or without
  @@ -10,7 +10,7 @@
    * are met:
    *
    * 1. Redistributions of source code must retain the above copyright
  - *    notice, this list of conditions and the following disclaimer. 
  + *    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
  @@ -18,7 +18,7 @@
    *    distribution.
    *
    * 3. The end-user documentation included with the redistribution,
  - *    if any, must include the following acknowledgment:  
  + *    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,
  @@ -26,7 +26,7 @@
    *
    * 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 
  + *    software without prior written permission. For written
    *    permission, please contact apache@apache.org.
    *
    * 5. Products derived from this software may not be called "Apache",
  @@ -166,8 +166,12 @@
         if ( "".equals(tmp) )
             tmp = req.getContextPath(); // Is this right?
         
  -      if ( tmp != null ) 
  +      if ( tmp != null )
           msgContext.setProperty( HTTPConstants.MC_HTTP_SOAPACTION, tmp );
  +        
  +        // Create a Session wrapper for the HTTP session.
  +        // These can/should be pooled at some point.  (Sam is Watching! :-)
  +        msgContext.setSession(new AxisHttpSession(req.getSession()));
   
         /* Save the real path */
         /**********************/
  @@ -189,7 +193,7 @@
           // It's been suggested that a lack of SOAPAction should produce some
           // other error code (in the 400s)...
         }
  -      else 
  +      else
           res.setStatus( HttpServletResponse.SC_INTERNAL_SERVER_ERROR );
         if ( !(e instanceof AxisFault) )
           e = new AxisFault( e );
  
  
  
  1.6       +14 -5     xml-axis/java/src/org/apache/axis/transport/http/HTTPConstants.java
  
  Index: HTTPConstants.java
  ===================================================================
  RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/transport/http/HTTPConstants.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- HTTPConstants.java	2001/03/08 01:15:22	1.5
  +++ HTTPConstants.java	2001/06/14 07:04:04	1.6
  @@ -2,7 +2,7 @@
    * The Apache Software License, Version 1.1
    *
    *
  - * Copyright (c) 1999 The Apache Software Foundation.  All rights 
  + * Copyright (c) 1999 The Apache Software Foundation.  All rights
    * reserved.
    *
    * Redistribution and use in source and binary forms, with or without
  @@ -10,7 +10,7 @@
    * are met:
    *
    * 1. Redistributions of source code must retain the above copyright
  - *    notice, this list of conditions and the following disclaimer. 
  + *    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
  @@ -18,7 +18,7 @@
    *    distribution.
    *
    * 3. The end-user documentation included with the redistribution,
  - *    if any, must include the following acknowledgment:  
  + *    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,
  @@ -26,7 +26,7 @@
    *
    * 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 
  + *    software without prior written permission. For written
    *    permission, please contact apache@apache.org.
    *
    * 5. Products derived from this software may not be called "Apache",
  @@ -57,7 +57,8 @@
   
   /**
    * HTTP protocol and message context constants.
  - *  
  + *
  + * @author Rob Jellinghaus (robj@unrealities.com)
    * @author Doug Davis (dug@us.ibm.com)
    * @author Jacek Kopecky (jacek@idoox.com)
    */
  @@ -75,6 +76,14 @@
       public static final String HEADER_CONTENT_ID = "Content-ID";
       public static final String HEADER_SOAP_ACTION = "SOAPAction";
       public static final String HEADER_AUTHORIZATION = "Authorization";
  +    
  +    /**
  +     * Cookie headers
  +     */
  +    public static final String HEADER_COOKIE = "Cookie";
  +    public static final String HEADER_COOKIE2 = "Cookie2";
  +    public static final String HEADER_SET_COOKIE = "Set-Cookie";
  +    public static final String HEADER_SET_COOKIE2 = "Set-Cookie2";
       
       /** Integer
        */
  
  
  
  1.26      +55 -1     xml-axis/java/src/org/apache/axis/transport/http/HTTPDispatchHandler.java
  
  Index: HTTPDispatchHandler.java
  ===================================================================
  RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/transport/http/HTTPDispatchHandler.java,v
  retrieving revision 1.25
  retrieving revision 1.26
  diff -u -r1.25 -r1.26
  --- HTTPDispatchHandler.java	2001/06/12 15:43:17	1.25
  +++ HTTPDispatchHandler.java	2001/06/14 07:04:05	1.26
  @@ -188,12 +188,33 @@
                       .append( Base64.encode( tmpBuf.toString().getBytes() ) )
                       .append("\n" );
         }
  +        
  +        // don't forget the cookies!
  +        // mmm... cookies
  +        if (msgContext.getMaintainSession()) {
  +            String cookie = msgContext.getStrProp(HTTPConstants.HEADER_COOKIE);
  +            String cookie2 = msgContext.getStrProp(HTTPConstants.HEADER_COOKIE2);
  +            
  +            if (cookie != null) {
  +                otherHeaders.append(HTTPConstants.HEADER_COOKIE)
  +                    .append(": ")
  +                    .append(cookie)
  +                    .append("\r\n");
  +            }
  +         
  +            if (cookie2 != null) {
  +                otherHeaders.append(HTTPConstants.HEADER_COOKIE2)
  +                    .append(": ")
  +                    .append(cookie2)
  +                    .append("\r\n");
  +            }
  +        }
        
         StringBuffer header = new StringBuffer();
   
         header.append( HTTPConstants.HEADER_POST )
               .append(" " )
  -            .append( ((tmpURL.getFile() == null || 
  +            .append( ((tmpURL.getFile() == null ||
                          tmpURL.getFile().equals(""))? "/": tmpURL.getFile()) )
               .append( " HTTP/1.0\r\n" )
               .append( HTTPConstants.HEADER_CONTENT_LENGTH )
  @@ -298,6 +319,19 @@
           }
   
           msgContext.setResponseMessage( outMsg );
  +         
  +          // if we are maintaining session state,
  +          // handle cookies (if any)
  +          if (msgContext.getMaintainSession()) {
  +              handleCookie(HTTPConstants.HEADER_COOKIE,
  +                           HTTPConstants.HEADER_SET_COOKIE,
  +                           headers,
  +                           msgContext);
  +              handleCookie(HTTPConstants.HEADER_COOKIE2,
  +                           HTTPConstants.HEADER_SET_COOKIE2,
  +                           headers,
  +                           msgContext);
  +          }
         }
       }
       catch( Exception e ) {
  @@ -308,9 +342,29 @@
       }
       Debug.Print( 1, "Exit: HTTPDispatchHandler::invoke" );
     }
  +    
  +    // little helper function for cookies
  +    public void handleCookie
  +        (String cookieName, String setCookieName, Hashtable headers,
  +         MessageContext msgContext)
  +    {
  +        if (headers.containsKey(setCookieName.toLowerCase())) {
  +            String cookie = (String)headers.get(setCookieName.toLowerCase());
  +            cookie = cookie.trim();
  +            // chop after first ; a la Apache SOAP (see HTTPUtils.java there)
  +            int index = cookie.indexOf(';');
  +            if (index != -1) {
  +                cookie = cookie.substring(0, index);
  +            }
  +            msgContext.setProperty(cookieName, cookie);
  +        }
  +    }
  +             
  +        
   
     public void undo(MessageContext msgContext) {
       Debug.Print( 1, "Enter: HTTPDispatchHandler::undo" );
       Debug.Print( 1, "Exit: HTTPDispatchHandler::undo" );
     }
   };
  +
  
  
  
  1.13      +182 -37   xml-axis/java/src/org/apache/axis/transport/http/SimpleAxisServer.java
  
  Index: SimpleAxisServer.java
  ===================================================================
  RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/transport/http/SimpleAxisServer.java,v
  retrieving revision 1.12
  retrieving revision 1.13
  diff -u -r1.12 -r1.13
  --- SimpleAxisServer.java	2001/06/12 15:43:18	1.12
  +++ SimpleAxisServer.java	2001/06/14 07:04:05	1.13
  @@ -63,13 +63,39 @@
   import org.apache.axis.server.* ;
   import org.apache.axis.utils.* ;
   
  +import org.apache.axis.session.Session;
  +import org.apache.axis.session.SimpleSession;
  +
   /**
    * This is a single threaded implementation of an HTTP server for processing
    * SOAP requests via Apache's xml-axis.  This is not intended for production
    * use.  Its intended uses are for demos, debugging, and performance
    * profiling.
  + *
  + * @author Sam Ruby (ruby@us.ibm.com)
  + * @author Rob Jellinghaus (robj@unrealities.com)
    */
   public class SimpleAxisServer implements Runnable {
  +    
  +    // session state.
  +    // This table maps session keys (random numbers) to SimpleAxisSession objects.
  +    //
  +    // There is NO CLEANUP of this table at present, and if clients are not
  +    // passing cookies, then a new session will be created for *every* request.
  +    // This is the biggest impediment to any kind of real SimpleAxisServer use.
  +    // So, if this becomes objectionable, we will implement some simpleminded
  +    // cleanup (perhaps just a cap on max # of sessions, and some kind of LRU
  +    // cleanup policy).
  +    private Hashtable sessions = new Hashtable();
  +    
  +    // Are we doing sessions?
  +    // Set this to false if you don't want any session overhead.
  +    public static boolean doSessions = true;
  +    
  +    // What is our current session index?
  +    // This is a monotonically increasing, non-thread-safe integer
  +    // (thread safety not considered crucial here)
  +    public static int sessionIndex = 0;
   
       // Axis server (shared between instances)
       private static AxisServer myAxisServer = null;
  @@ -131,10 +157,12 @@
           NonBlockingBufferedInputStream is =
               new NonBlockingBufferedInputStream();
   
  -        // SoapAction
  +        // buffers for the headers we care about
           StringBuffer soapAction = new StringBuffer();
           StringBuffer httpRequest = new StringBuffer();
  -
  +        StringBuffer cookie = new StringBuffer();
  +        StringBuffer cookie2 = new StringBuffer();
  +        
           // Accept and process requests from the socket
           while (!stopped) {
               Socket socket = null;
  @@ -152,6 +180,7 @@
               msgContext.setProperty("transport", "HTTPTransport");
               msgContext.setProperty(MessageContext.TRANS_INPUT, transportInName);
               msgContext.setProperty(MessageContext.TRANS_OUTPUT, transportOutName);
  +            
               try {
                   try {
                       socket = serverSocket.accept();
  @@ -162,10 +191,21 @@
                   // assume the best
                   byte[] status = OK;
   
  +                // cookie for this session, if any
  +                String cooky = null;
  +                
                   try {
  +                    // wipe cookies if we're doing sessions
  +                    if (doSessions) {
  +                        cookie.delete(0, cookie.length());
  +                        cookie2.delete(0, cookie.length());
  +                    }
  +                    
                       // read headers
                       is.setInputStream(socket.getInputStream());
  -                    int contentLength = parseHeaders(is, soapAction, httpRequest);
  +                    // parse all headers into hashtable
  +                    int contentLength = parseHeaders(is, soapAction, httpRequest,
  +                        cookie, cookie2);
                       is.setContentLength(contentLength);
   
                       // if get, then return simpleton document as response
  @@ -181,15 +221,45 @@
                           continue;
                       }
                           
  -                    // set up request
  -                    
  -                    
                       String soapActionString = soapAction.toString();
                       requestMsg = new Message(is);
                       msgContext.setRequestMessage(requestMsg);
                       msgContext.setTargetService(soapActionString);
                       msgContext.setProperty(HTTPConstants.MC_HTTP_SOAPACTION,
                                              soapActionString);
  +                    
  +                    // set up session, if any
  +                    if (doSessions) {
  +                        // did we get a cookie?
  +                        if (cookie.length() > 0) {
  +                            cooky = cookie.toString().trim();
  +                        } else if (cookie2.length() > 0) {
  +                            cooky = cookie2.toString().trim();
  +                        }
  +                        
  +                        // if cooky is null, cook up a cooky
  +                        if (cooky == null) {
  +                            // fake one up!
  +                            // make it be an arbitrarily increasing number
  +                            // (no this is not thread safe because ++ isn't atomic)
  +                            int i = sessionIndex++;
  +                            cooky = "" + i;
  +                        }
  +                            
  +                        // is there a session already?
  +                        Session session = null;
  +                        if (sessions.containsKey(cooky)) {
  +                            session = (Session)sessions.get(cooky);
  +                        } else {
  +                            // no session for this cooky, bummer
  +                            session = new SimpleSession();
  +                            
  +                            // ADD CLEANUP LOGIC HERE if needed
  +                            sessions.put(cooky, session);
  +                        }
  +                        
  +                        msgContext.setSession(session);
  +                    }
   
                       // invoke the Axis engine
                       engine.invoke(msgContext);
  @@ -219,6 +289,20 @@
                   out.write(status);
                   out.write(MIME_STUFF);
                   putInt(out, response.length);
  +                
  +                if (doSessions) {
  +                    // write cookie headers, if any
  +                    // don't sweat efficiency *too* badly
  +                    // optimize at will
  +                    StringBuffer cookieOut = new StringBuffer();
  +                    cookieOut.append("\r\nSet-Cookie: ")
  +                        .append(cooky)
  +                        .append("\r\nSet-Cookie2: ")
  +                        .append(cooky);
  +                    // OH, THE HUMANITY!  yes this is inefficient.
  +                    out.write(cookieOut.toString().getBytes());
  +                }
  +                
                   out.write(SEPARATOR);
                   out.write(response);
                   out.flush();
  @@ -260,14 +344,25 @@
       private static final int lenLen = lenHeader.length;
   
       // mime header for soap action
  -    private static final byte actionHeader[] = "soapaction: \"".getBytes();
  +    private static final byte actionHeader[] = "soapaction: ".getBytes();
       private static final int actionLen = actionHeader.length;
       
  +    // mime header for cookie
  +    private static final byte cookieHeader[] = "cookie: ".getBytes();
  +    private static final int cookieLen = cookieHeader.length;
  +    
  +    // mime header for cookie2
  +    private static final byte cookie2Header[] = "cookie2: ".getBytes();
  +    private static final int cookie2Len = cookie2Header.length;
  +    
       // mime header for GET
       private static final byte getHeader[] = "GET".getBytes();
   
       // mime header for POST
       private static final byte postHeader[] = "POST".getBytes();
  +    
  +    // header ender
  +    private static final byte headerEnder[] = ": ".getBytes();
   
       // buffer for IO
       private static final int BUFSIZ = 4096;
  @@ -299,9 +394,15 @@
        * @param is         InputStream to read from
        * @param soapAction StringBuffer to return the soapAction into
        * @param httpRequest StringBuffer for GET / POST
  +     * @param cookie first cookie header (if doSessions)
  +     * @param cookie2 second cookie header (if doSessions)
        * @return Content-Length
        */
  -    private int parseHeaders(InputStream is, StringBuffer soapAction, StringBuffer httpRequest)
  +    private int parseHeaders(InputStream is,
  +                             StringBuffer soapAction,
  +                             StringBuffer httpRequest,
  +                             StringBuffer cookie,
  +                             StringBuffer cookie2)
         throws IOException
       {
           int n;
  @@ -328,41 +429,85 @@
           
           while ((n=readLine(is,buf,0,buf.length)) > 0) {
           
  -            int lenMatch = 0;
  -            int actionMatch = 0;
  -            int getMatch = 0;
  -            for (int i=0; i<n; i++) {
  -                byte c = toLower[buf[i]];
  -
  -                if (actionMatch==0 && c==lenHeader[lenMatch]) {
  -                    lenMatch++;
  -                    actionMatch=0;
  -                    if (lenMatch == lenLen) {
  -                        while ((++i<n) && (buf[i]>='0') && (buf[i]<='9')) {
  -                            len = (len*10) + (buf[i]-'0');
  -                        }
  -                        break;
  -                    }
  -                } else if (c==actionHeader[actionMatch]) {
  -                    lenMatch=0;
  -                    actionMatch++;
  -                    if (actionMatch == actionLen) {
  -                        soapAction.delete(0,soapAction.length());
  -                        while ((++i<n) && (buf[i]!='"') && (buf[i]!='9')) {
  -                            soapAction.append((char)(buf[i] & 0x7f));
  -                        }
  -                        break;
  -                    }
  -                } else {
  -                    lenMatch=0;
  -                    actionMatch=0;
  +            // if we are at the separator blank line, bail right now
  +            if ((n<=2) && (buf[0]=='\n'||buf[0]=='\r') && (len>0)) break;
  +            
  +            // RobJ gutted the previous logic; it was too hard to extend for more headers.
  +            // Now, all it does is search forwards for ": " in the buf,
  +            // then do a length / byte compare.
  +            // Hopefully this is still somewhat efficient (Sam is watching!).
  +            
  +            // First, search forwards for ": "
  +            int endHeaderIndex = 0;
  +            while (endHeaderIndex < n && toLower[buf[endHeaderIndex]] != headerEnder[0]) {
  +                endHeaderIndex++;
  +            }
  +            endHeaderIndex += 2;
  +            // endHeaderIndex now points _just past_ the ": ", and is
  +            // comparable to the various lenLen, actionLen, etc. values
  +            
  +            // convenience; i gets pre-incremented, so initialize it to one less
  +            int i = endHeaderIndex - 1;
  +            
  +            // which header did we find?
  +            if (endHeaderIndex == lenLen && matches(buf, lenHeader)) {
  +                // parse content length
  +                
  +                while ((++i<n) && (buf[i]>='0') && (buf[i]<='9')) {
  +                    len = (len*10) + (buf[i]-'0');
  +                }
  +                
  +            }
  +            else if (endHeaderIndex == actionLen
  +                       && matches(buf, actionHeader))
  +            {
  +                           
  +                soapAction.delete(0,soapAction.length());
  +                // skip initial '"'
  +                i++;
  +                while ((++i<n) && (buf[i]!='"')) {
  +                    soapAction.append((char)(buf[i] & 0x7f));
  +                }
  +                           
  +            }
  +            else if (doSessions && endHeaderIndex == cookieLen
  +                       && matches(buf, cookieHeader))
  +            {
  +                           
  +                // keep everything up to first ;
  +                while ((++i<n) && (buf[i]!=';') && (buf[i]!='\r') && (buf[i]!='\n')) {
  +                    cookie.append((char)(buf[i] & 0x7f));
                   }
  +                           
               }
  +            else if (doSessions && endHeaderIndex == cookie2Len
  +                       && matches(buf, cookie2Header))
  +            {
  +                           
  +                // keep everything up to first ;
  +                while ((++i<n) && (buf[i]!=';') && (buf[i]!='\r') && (buf[i]!='\n')) {
  +                    cookie2.append((char)(buf[i] & 0x7f));
  +                }
  +                           
  +            }
   
  -            if ((n<=2) && (buf[0]=='\n'||buf[0]=='\r') && (len>0)) break;
           }
           return len;
       }
  +    
  +    
  +    /**
  +     * does tolower[buf] match the target byte array, up to the target's length?
  +     */
  +    public boolean matches (byte[] buf, byte[] target) {
  +        for (int i = 0; i < target.length; i++) {
  +            if (toLower[buf[i]] != target[i]) {
  +                return false;
  +            }
  +        }
  +        return true;
  +    }
  +
   
       /**
        * output an integer into the output stream
  
  
  
  1.3       +6 -6      xml-axis/java/src/org/apache/axis/transport/http/AxisHttpSession.java
  
  Index: AxisHttpSession.java
  ===================================================================
  RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/transport/http/AxisHttpSession.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- AxisHttpSession.java	2001/06/12 22:29:49	1.2
  +++ AxisHttpSession.java	2001/06/14 07:04:06	1.3
  @@ -60,7 +60,7 @@
   
   /**
    * An HTTP/Servlet implementation of Axis sessions.
  - * 
  + *
    * @author Glen Daniels (gdaniels@macromedia.com)
    */
   public class AxisHttpSession implements Session
  @@ -82,7 +82,7 @@
       }
       
       /** Get a property from the session
  -     * 
  +     *
        * @param key the name of the property desired.
        */
       public Object get(String key)
  @@ -91,17 +91,17 @@
       }
       
       /** Set a property in the session
  -     * 
  +     *
        * @param key the name of the property to set.
        * @param value the value of the property.
        */
  -    public void put(String key, Object value)
  +    public void set(String key, Object value)
       {
           rep.setAttribute(key, value);
       }
       
       /** Remove a property from the session
  -     * 
  +     *
        * @param key the name of the property desired.
        */
       public void remove(String key)
  @@ -110,7 +110,7 @@
       }
       
       /** Set the session's time-to-live.
  -     * 
  +     *
        * This is implementation-specific, but basically should be the #
        * of seconds of inactivity which will cause the session to time
        * out and invalidate.  "inactivity" is implementation-specific.
  
  
  
  1.3       +55 -5     xml-axis/java/src/org/apache/axis/providers/java/JavaProvider.java
  
  Index: JavaProvider.java
  ===================================================================
  RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/providers/java/JavaProvider.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- JavaProvider.java	2001/06/12 15:43:16	1.2
  +++ JavaProvider.java	2001/06/14 07:04:10	1.3
  @@ -84,12 +84,62 @@
        * Get the service object whose method actually provides the service.
        * May look up in session table.
        */
  -    public Object getServiceObject (MessageContext msgContext, String clsName, String methodName, JavaClass jc)
  +    public Object getServiceObject (MessageContext msgContext, Handler service, JavaClass jc, String clsName)
           throws Exception
       {
  -        // default is just to get new instance, for now
  -        // soon, session support here
  -        return jc.getJavaClass().newInstance();
  +        String serviceName = msgContext.getTargetService();
  +        
  +        // scope can be "Request", "Session", "Application" (as with Apache SOAP)
  +        String scope = (String)service.getOption("scope");
  +        if (scope == null) {
  +            // default is Request scope
  +            scope = "Request";
  +        }
  +        
  +        if (scope.equals("Request")) {
  +            
  +            // make a one-off
  +            return jc.getJavaClass().newInstance();
  +            
  +        } else if (scope.equals("Session")) {
  +            
  +            // look in incoming session
  +            if (msgContext.getSession() != null) {
  +                // store service objects in session, indexed by class name
  +                Object obj = msgContext.getSession().get(serviceName);
  +                if (obj == null) {
  +                    obj = jc.getJavaClass().newInstance();
  +                    msgContext.getSession().set(serviceName, obj);
  +                }
  +                return obj;
  +            } else {
  +                // was no incoming session, sigh, treat as request scope
  +                return jc.getJavaClass().newInstance();
  +            }
  +            
  +        } else if (scope.equals("Application")) {
  +            
  +            // MUST be AxisEngine here!
  +            AxisEngine engine = msgContext.getAxisEngine();
  +            if (engine.getApplicationSession() != null) {
  +                // store service objects in session, indexed by class name
  +                Object obj = engine.getApplicationSession().get(serviceName);
  +                if (obj == null) {
  +                    obj = jc.getJavaClass().newInstance();
  +                    engine.getApplicationSession().set(serviceName, obj);
  +                }
  +                return obj;
  +            } else {
  +                // was no incoming session, sigh, treat as request scope
  +                return jc.getJavaClass().newInstance();
  +            }
  +            
  +        } else {
  +            
  +            // NOTREACHED
  +            return null;
  +            
  +        }
       }
       
       
  @@ -140,7 +190,7 @@
               AxisClassLoader cl     = msgContext.getClassLoader();
               JavaClass       jc     = cl.lookup(clsName);
               Class           cls    = jc.getJavaClass();
  -            Object          obj    = getServiceObject(msgContext, clsName, methodName, jc);
  +            Object          obj    = getServiceObject(msgContext, service, jc, clsName);
               
               Message         reqMsg  = msgContext.getRequestMessage();
               SOAPEnvelope    reqEnv  = (SOAPEnvelope) reqMsg.getAsSOAPEnvelope();
  
  
  
  1.5       +25 -2     xml-axis/java/src/org/apache/axis/providers/java/RPCProvider.java
  
  Index: RPCProvider.java
  ===================================================================
  RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/providers/java/RPCProvider.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- RPCProvider.java	2001/06/05 11:52:31	1.4
  +++ RPCProvider.java	2001/06/14 07:04:10	1.5
  @@ -125,6 +125,29 @@
                   }
               }
               
  +            // methodName may be a comma-delimited string of method names.
  +            // If so, look for the one matching mname.
  +            if (methodName != null && methodName.indexOf(' ') != -1) {
  +                StringTokenizer tok = new StringTokenizer(methodName, " ");
  +                String nextMethodName = null;
  +                while (tok.hasMoreElements()) {
  +                    String token = tok.nextToken();
  +                    if (token.equals(mName)) {
  +                        nextMethodName = token;
  +                        break;
  +                    }
  +                }
  +                // didn't find a matching one...
  +                if (nextMethodName == null) {
  +                    throw new AxisFault( "AxisServer.error",
  +                                        "Method names don't match\n" +
  +                                            "Body method name=" + mName + "\n" +
  +                                            "Service method names=" + methodName,
  +                                        null, null );  // should they??
  +                }
  +                methodName = nextMethodName;
  +            }
  +            
               if ( methodName != null && !methodName.equals(mName) )
                   throw new AxisFault( "AxisServer.error",
                                       "Method names don't match\n" +
  @@ -150,8 +173,8 @@
               // If method has an additional parameter of the right parameter
               // type, add MessageContext as the first parameter
               Class params[] = method.getParameterTypes();
  -            if (params.length > args.size() 
  -              && params[0].equals(msgContext.getClass())) 
  +            if (params.length > args.size()
  +              && params[0].equals(msgContext.getClass()))
               {
                 args.add( 0, msgContext );
                 method = jc.getMethod(mName, args.size());
  
  
  
  1.2       +7 -7      xml-axis/java/src/org/apache/axis/session/Session.java
  
  Index: Session.java
  ===================================================================
  RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/session/Session.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- Session.java	2001/06/12 22:22:21	1.1
  +++ Session.java	2001/06/14 07:04:12	1.2
  @@ -57,34 +57,34 @@
   
   /**
    * An abstract interface to provide session storage to Axis services.
  - * 
  + *
    * This is extremely basic at the moment.
  - * 
  + *
    * @author Glen Daniels (gdaniels@macromedia.com)
    */
   public interface Session
   {
       /** Get a property from the session
  -     * 
  +     *
        * @param key the name of the property desired.
        */
       public Object get(String key);
       
       /** Set a property in the session
  -     * 
  +     *
        * @param key the name of the property to set.
        * @param value the value of the property.
        */
  -    public void put(String key, Object value);
  +    public void set(String key, Object value);
       
       /** Remove a property from the session
  -     * 
  +     *
        * @param key the name of the property desired.
        */
       public void remove(String key);
   
       /** Set the session's time-to-live.
  -     * 
  +     *
        * This is implementation-specific, but basically should be the #
        * of seconds of inactivity which will cause the session to time
        * out and invalidate.  "inactivity" is implementation-specific.
  
  
  
  1.2       +6 -6      xml-axis/java/src/org/apache/axis/session/SimpleSession.java
  
  Index: SimpleSession.java
  ===================================================================
  RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/session/SimpleSession.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- SimpleSession.java	2001/06/12 22:22:21	1.1
  +++ SimpleSession.java	2001/06/14 07:04:13	1.2
  @@ -59,7 +59,7 @@
   
   /**
    * A trivial session implementation.
  - * 
  + *
    * @author Glen Daniels (gdaniels@macromedia.com)
    */
   public class SimpleSession implements Session
  @@ -73,7 +73,7 @@
       private long lastTouched;
                             
       /** Get a property from the session
  -     * 
  +     *
        * @param key the name of the property desired.
        */
       public Object get(String key)
  @@ -85,11 +85,11 @@
       }
       
       /** Set a property in the session
  -     * 
  +     *
        * @param key the name of the property to set.
        * @param value the value of the property.
        */
  -    public void put(String key, Object value)
  +    public void set(String key, Object value)
       {
           if (rep == null)
               rep = new Hashtable();
  @@ -98,7 +98,7 @@
       }
       
       /** Remove a property from the session
  -     * 
  +     *
        * @param key the name of the property desired.
        */
       public void remove(String key)
  @@ -109,7 +109,7 @@
       }
       
       /** Set the session's time-to-live.
  -     * 
  +     *
        * This is implementation-specific, but basically should be the #
        * of seconds of inactivity which will cause the session to time
        * out and invalidate.  "inactivity" is implementation-specific.
  
  
  
  1.4       +3 -0      xml-axis/java/test/functional/FunctionalTests.java
  
  Index: FunctionalTests.java
  ===================================================================
  RCS file: /home/cvs/xml-axis/java/test/functional/FunctionalTests.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- FunctionalTests.java	2001/06/02 04:01:20	1.3
  +++ FunctionalTests.java	2001/06/14 07:04:15	1.4
  @@ -37,6 +37,9 @@
           // bid-buy test
           suite.addTestSuite(TestBidBuySample.class);
   
  +        // address book test
  +        suite.addTestSuite(TestAddressBookSample.class);
  +
           return suite;
       }
   }
  
  
  
  1.1                  xml-axis/java/test/functional/TestAddressBookSample.java
  
  Index: TestAddressBookSample.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999 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 test.functional;
  
  import java.net.*;
  import java.io.*;
  import java.util.*;
  
  import org.apache.axis.AxisFault ;
  import org.apache.axis.client.http.AdminClient;
  import org.apache.axis.utils.Debug ;
  import org.apache.axis.utils.Options ;
  import org.apache.axis.utils.QName ;
  import org.apache.axis.encoding.ServiceDescription;
  import org.apache.axis.encoding.SOAPTypeMappingRegistry;
  
  import junit.framework.TestCase;
  
  import samples.addressbook.Main;
  
  /** Test the address book sample code.
   */
  public class TestAddressBookSample extends TestCase {
      
      public TestAddressBookSample(String name) {
          super(name);
      }
      
      public void doTestDeploy () throws Exception {
          String[] args = { "samples/addressbook/deploy.xml" };
          new AdminClient().doAdmin(args);
      }
      
      public void doTest () throws Exception {
          String[] args = {};
          Main.main(args);
      }
      
      public void testAddressBookService () throws Exception {
          try {
              System.out.println("Testing address book sample.");
              System.out.println("Testing deployment...");
              doTestDeploy();
              System.out.println("Testing service...");
              doTest();
              System.out.println("Test complete.");
          }
          catch( Exception e ) {
              if ( e instanceof AxisFault ) ((AxisFault)e).dump();
              e.printStackTrace();
              throw new Exception("Fault returned from test: "+e);
          }
      }
      
  }
  
  
  
  
  1.2       +1 -1      xml-axis/java/test/session/TestSimpleSession.java
  
  Index: TestSimpleSession.java
  ===================================================================
  RCS file: /home/cvs/xml-axis/java/test/session/TestSimpleSession.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- TestSimpleSession.java	2001/06/12 22:26:54	1.1
  +++ TestSimpleSession.java	2001/06/14 07:04:17	1.2
  @@ -16,7 +16,7 @@
       public void testSession() {
           SimpleSession session = new SimpleSession();
           Object val = new Float(5.6666);
  -        session.put("test", val);
  +        session.set("test", val);
           
           assertEquals(val, session.get("test"));