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 wh...@apache.org on 2002/10/03 11:20:47 UTC

cvs commit: xml-axis-wsif/java/test/inout/wsiftypes InoutImpl.java

whitlock    2002/10/03 02:20:47

  Modified:    java/test/inout/wsifservice Inout.wsdl
                        DeploymentDescriptor.xml
               java/test/inout/wsiftypes InoutImpl.java
  Added:       java/test/proposals/mime WSIFJmsSender.java MimeTest.java
                        test.txt WSIFDynamicProvider_ApacheAxis.java
                        WSIFJmsTransport.java WSIFPort_ApacheAxis.java
                        WSIFOperation_ApacheAxis.java
  Log:
  Add mime support
  
  Revision  Changes    Path
  1.1                  xml-axis-wsif/java/test/proposals/mime/WSIFJmsSender.java
  
  Index: WSIFJmsSender.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 2002 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 "WSIF" 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) 2001, 2002, International
   * Business Machines, Inc., http://www.apache.org.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  package proposals.mime;
  
  import java.io.Serializable;
  
  import org.apache.axis.AxisFault;
  import org.apache.axis.Message;
  import org.apache.axis.MessageContext;
  import org.apache.axis.handlers.BasicHandler;
  import org.apache.wsif.WSIFCorrelationId;
  import org.apache.wsif.WSIFCorrelationService;
  import org.apache.wsif.WSIFException;
  import org.apache.wsif.logging.Trc;
  import org.apache.wsif.util.WSIFCorrelationServiceLocator;
  import org.apache.wsif.util.WSIFProperties;
  import org.apache.wsif.util.jms.WSIFJMSCorrelationId;
  import org.apache.wsif.util.jms.WSIFJMSDestination;
  
  /**
   * @author Mark Whitlock <wh...@apache.org>
   */
  public class WSIFJmsSender extends BasicHandler {
      private static final long ASYNC_TIMEOUT = WSIFProperties.getAsyncTimeout();
      private static final String DUMMY_RESPONSE =
          "<?xml version='1.0' encoding='UTF-8'?>\n<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/1999/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/1999/XMLSchema\">\n<SOAP-ENV:Body>\n<ns1:addEntryResponse xmlns:ns1=\"http://wsifservice.addressbook/\" SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n</ns1:addEntryResponse>\n\n</SOAP-ENV:Body>\n</SOAP-ENV:Envelope>";
  
      public void invoke(MessageContext messageContext) throws AxisFault {
          Trc.entry(this, messageContext);
          try {
              // Determine if this is an async operation
              boolean asyncMode =
                  messageContext.isPropertyTrue(WSIFJmsTransport.ASYNCOPERATION);
              WSIFJMSDestination dest =
                  (WSIFJMSDestination) messageContext.getProperty(WSIFJmsTransport.DESTINATION);
  
              Message message = messageContext.getRequestMessage();
              String contents = message.getSOAPPartAsString();
  
              if (asyncMode) {
                  performAsyncSend(messageContext, dest, contents);
              } else {
                  String id = dest.send(contents, null);
                  String response = dest.receiveString(id);
                  Message responseMessage = new Message(response);
                  messageContext.setResponseMessage(responseMessage);
              }
          } catch (WSIFException we) {
          	Trc.exception(we);
              throw new AxisFault(we.toString());
          }
          Trc.exit();
      }
  
      public void undo(MessageContext messageContext) {
          Trc.entry(this, messageContext);
          Trc.exit();
      }
  
      /**
       * Send the request asynchronously.
       * If there is a WISFResponseHandler associated with the operation then
       * the the WSIFOperation is stored in the correlation service with the JMS 
       * messgage ID of the request. A listener is then set to listen for the 
       * response to the request and when the response arrives the listener 
       * looks up the responses ID in the correlation service and forwards 
       * the response to the associated WSIFOperation.
       */
      private void performAsyncSend(
          MessageContext messageContext,
          WSIFJMSDestination dest,
          String data)
          throws WSIFException {
          String msgID;
  
          WSIFOperation_ApacheAxis wsifOp =
              (WSIFOperation_ApacheAxis) messageContext.getProperty(
                  WSIFJmsTransport.WSIFOPERATION);
  
          WSIFCorrelationId cid;
  
          // only save op in the correlation service if there's a response handler
          if ( wsifOp.getResponseHandler() == null ) {
             msgID = dest.send( data );
             cid = new WSIFJMSCorrelationId( msgID );
          } else {
             WSIFCorrelationService correlator = 
                WSIFCorrelationServiceLocator.getCorrelationService();
             synchronized( correlator ) {   
                msgID = dest.send( data );
                cid = new WSIFJMSCorrelationId( msgID );
                if ( correlator != null ) {
                   correlator.put( cid, (Serializable)wsifOp, ASYNC_TIMEOUT );
                }
             }
          }
            
  
          // Save msg ID in the WSIFop for this calling client
          wsifOp.setAsyncRequestID(new WSIFJMSCorrelationId(msgID));
  
          // Axis doesn't like a null response so give it something
          Message responseMessage = new Message(DUMMY_RESPONSE);
          messageContext.setResponseMessage(responseMessage);
      }
  }
  
  
  1.1                  xml-axis-wsif/java/test/proposals/mime/MimeTest.java
  
  Index: MimeTest.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 2002 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 "WSIF" 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) 2001, 2002, International
   * Business Machines, Inc., http://www.apache.org.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  package proposals.mime;
  
  import inout.wsifservice.Inout;
  import java.io.BufferedInputStream;
  import java.io.File;
  import java.io.FileInputStream;
  import java.util.Arrays;
  
  import javax.activation.DataHandler;
  import javax.activation.FileDataSource;
  import javax.xml.namespace.QName;
  import junit.framework.Test;
  import junit.framework.TestCase;
  import junit.framework.TestSuite;
  
  import org.apache.wsif.WSIFService;
  import org.apache.wsif.WSIFServiceFactory;
  import org.apache.wsif.util.WSIFPluggableProviders;
  import util.TestUtilities;
  
  /**
   * Junit test to test out the Inout test
   * @author Mark Whitlock
   */
  public class MimeTest extends TestCase {
      String wsdlLocation =
          TestUtilities.getWsdlPath("java\\test\\inout\\wsifservice") + "Inout.wsdl";
  
      private final static String FILE = "file";
      private final static String filename =
          TestUtilities.getWsdlPath("java\\test\\proposals\\mime") + "test.txt";
  
      private final static String RPC = "rpc";
      private final static String DOC = "doc";
  
      private final static String SOAP = "soap";
      private final static String AXIS = "axis";
      private final static String JAVA = "java";
      private final static String NJMS = "nativeJMS";
  
      private interface InoutMime extends Inout {
          public String fileToString(DataHandler dh);
      }
  
      public MimeTest(String name) {
          super(name);
      }
  
      public static void main(String[] args) {
          junit.textui.TestRunner.run(suite());
      }
  
      public static Test suite() {
          return new TestSuite(MimeTest.class);
      }
  
      public void setUp() {
          TestUtilities.setUpExtensionsAndProviders();
      }
  
      public void testAxis() {
          doit("SOAPPort", AXIS, RPC, FILE);
      }
  
      private void doit(
          String portName,
          String protocol,
          String style,
          String cmd) {
  
          WSIFDynamicProvider_ApacheAxis provider =
              new WSIFDynamicProvider_ApacheAxis();
          WSIFPluggableProviders.overrideDefaultProvider(
              "http://schemas.xmlsoap.org/wsdl/soap/",
              provider);
  
          try {
              WSIFServiceFactory factory = WSIFServiceFactory.newInstance();
              WSIFService service =
                  factory.getService(
                      wsdlLocation,
                      null,
                      null,
                      "http://wsifservice.inout/",
                      "Inout");
  
              service.mapType(
                  new QName("http://wsiftypes.inout/", "arrayofint"),
                  Class.forName("[I"));
  
              service.mapType(
                  new QName("http://wsiftypes.inout/", "datahandler"),
                  DataHandler.class);
  
              InoutMime stub =
                  (InoutMime) service.getStub(portName, InoutMime.class);
  
              if (cmd.equals(FILE))
                  file(stub);
              else
                  assertTrue(false);
  
          } catch (Exception e) {
              System.err.println(
                  "MimeTest(" + portName + ") caught exception " + e);
              e.printStackTrace();
              assertTrue(false);
          } finally {
              if (protocol.equals(SOAP) || protocol.equals(AXIS)) {
                  WSIFPluggableProviders.overrideDefaultProvider(
                      "http://schemas.xmlsoap.org/wsdl/soap/",
                      null);
              }
          }
  
      }
  
      private void file(InoutMime stub) throws Exception {
          DataHandler dh = new DataHandler(new FileDataSource(filename));
          String buff = stub.fileToString(dh);
          compareFiles(filename, buff);
      }
  
      protected boolean compareFiles(String one, String buff)
          throws java.io.FileNotFoundException, java.io.IOException {
  
          BufferedInputStream oneStream = null;
          File f1 = new File(one);
  
          try {
              oneStream =
                  new BufferedInputStream(
                      new FileInputStream(one),
                      buff.length());
  
              byte[] bufOne = new byte[buff.length()];
              int bread = -1;
  
              if (0 == oneStream.available())
                  return false;
  
              Arrays.fill(bufOne, (byte) 0);
  
              bread = oneStream.read(bufOne, 0, bufOne.length);
              String sOne = new String(bufOne);
              if (!sOne.equals(buff))
                  return false;
              return true;
          } finally {
              if (null != oneStream)
                  oneStream.close();
          }
      }
  }
  
  
  
  1.1                  xml-axis-wsif/java/test/proposals/mime/test.txt
  
  Index: test.txt
  ===================================================================
  Hello Mark
  
  
  1.1                  xml-axis-wsif/java/test/proposals/mime/WSIFDynamicProvider_ApacheAxis.java
  
  Index: WSIFDynamicProvider_ApacheAxis.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 2002 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 "WSIF" 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) 2001, 2002, International
   * Business Machines, Inc., http://www.apache.org.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  package proposals.mime;
  
  import java.security.AccessController;
  import java.security.PrivilegedAction;
  import java.util.Iterator;
  import java.util.List;
  import java.util.Vector;
  
  import javax.wsdl.Binding;
  import javax.wsdl.Definition;
  import javax.wsdl.Port;
  import javax.wsdl.Service;
  import javax.wsdl.extensions.soap.SOAPBinding;
  
  import org.apache.wsif.WSIFException;
  import org.apache.wsif.WSIFPort;
  import org.apache.wsif.base.WSIFServiceImpl;
  import org.apache.wsif.logging.Trc;
  import org.apache.wsif.providers.WSIFDynamicTypeMap;
  import org.apache.wsif.spi.WSIFProvider;
  
  /**
   * @author Owen Burroughs <ow...@apache.org>
   * @author Ant Elder <an...@apache.org>
   * @author Jeremy Hughes <hu...@apache.org>
   * @author Mark Whitlock <wh...@apache.org>
  */
  public class WSIFDynamicProvider_ApacheAxis implements WSIFProvider {
      private static final String soap = "http://schemas.xmlsoap.org/wsdl/soap/";
      private static final String jms = "http://schemas.xmlsoap.org/wsdl/jms/";
      private static String[] bindings = new String[0];
      private static String[] addresses = new String[0];
      private static boolean setUpBindings = false;
      private static boolean setUpAddresses = false;
  
      public WSIFDynamicProvider_ApacheAxis() {
          Trc.entry(this);
          if (!setUpBindings) {
              setUpBindingNamespaceURIs();
          }
          if (!setUpAddresses) {
              setUpAddressNamespaceURIs();
          }        
          WSIFServiceImpl.addExtensionRegistry(
              new org.apache.wsif.wsdl.extensions.jms.JMSExtensionRegistry());
          Trc.exit();
      }
  
      public WSIFPort createDynamicWSIFPort(
          Definition definition,
          Service service,
          Port port,
          WSIFDynamicTypeMap wsifdynamictypemap)
          throws WSIFException {
          Trc.entry(this, definition, service, port, wsifdynamictypemap);
          Binding binding = port.getBinding();
          List list = binding.getExtensibilityElements();
          for (Iterator iterator = list.iterator(); iterator.hasNext();) {
              Object obj = iterator.next();
              if (obj instanceof SOAPBinding) {
                  WSIFPort wp =
                      new WSIFPort_ApacheAxis(definition, service, port, wsifdynamictypemap);
                  Trc.exit(wp);
                  return wp;
              }
          }
  
          Trc.exit(null);
          return null;
      }
  
      /**
       * Returns the WSDL namespace URIs of any bindings this provider supports.
       * @return an array of all binding namespaces supported by this provider
       */
      public String[] getBindingNamespaceURIs() {
          Trc.entry(this);
          Trc.exit(bindings);
          return bindings;
      }
  
      /**
       * Returns the WSDL namespace URIs of any port addresses this provider supports.
       * @return an array of all address namespaces supported by this provider
       */
      public String[] getAddressNamespaceURIs() {
          Trc.entry(this);
          Trc.exit(addresses);
          return addresses;
      }
  
      private void setUpBindingNamespaceURIs() {
          // check if the axis classes are available, if not then we cannot
          // support soap bindings!        
          Class cls =
              (Class) AccessController.doPrivileged(new PrivilegedAction() {
              public Object run() {
                  try {
                      return Class.forName(
                          "org.apache.axis.AxisEngine",
                          true,
                          Thread.currentThread().getContextClassLoader());
                  } catch (Throwable ignored) {
                    	Trc.ignoredException(ignored);
                  }
                  return null;
              }
          });
          if (cls != null) {
              bindings = new String[] { soap };
          }
          setUpBindings = true;
      }
  
      private void setUpAddressNamespaceURIs() {
          Vector v = new Vector();
          // check if the jms classes are available, if not then we cannot
          // support jms addresses!        
          Class cls =
              (Class) AccessController.doPrivileged(new PrivilegedAction() {
              public Object run() {
                  try {
                      return Class.forName(
                          "javax.jms.Queue",
                          true,
                          Thread.currentThread().getContextClassLoader());
                  } catch (Throwable ignored) {
  		        	Trc.ignoredException(ignored);
                  }
                  return null;
              }
          });
          if (cls != null) {
          	v.add(jms);
          }
                          
          // check if the axis classes are available, if not then we cannot
          // support soap addresses!         
          Class cls2 =
              (Class) AccessController.doPrivileged(new PrivilegedAction() {
              public Object run() {
                  try {
                      return Class.forName(
                          "org.apache.axis.AxisEngine",
                          true,
                          Thread.currentThread().getContextClassLoader());
                  } catch (Throwable ignored) {
                   	Trc.ignoredException(ignored);
                  }
                  return null;
              }
          });
          if (cls2 != null) {
          	v.add(soap);
          }         
          addresses = null;
          addresses = new String[v.size()];
          for (int i = 0; i < v.size(); i++) {
              addresses[i] = (String) v.elementAt(i);
          }
          setUpAddresses = true;
      }
  }
  
  
  1.1                  xml-axis-wsif/java/test/proposals/mime/WSIFJmsTransport.java
  
  Index: WSIFJmsTransport.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 2002 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 "WSIF" 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) 2001, 2002, International
   * Business Machines, Inc., http://www.apache.org.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  package proposals.mime;
  
  import org.apache.axis.AxisEngine;
  import org.apache.axis.AxisFault;
  import org.apache.axis.MessageContext;
  import org.apache.axis.client.Call;
  import org.apache.axis.client.Transport;
  import org.apache.wsif.WSIFOperation;
  import org.apache.wsif.logging.Trc;
  import org.apache.wsif.util.jms.WSIFJMSDestination;
  
  /**
   * @author Mark Whitlock <wh...@apache.org>
   */
  public class WSIFJmsTransport extends Transport {
      private WSIFJMSDestination destination = null;
      private String asyncOperation = "false";
      private WSIFOperation wsifOperation = null;
  
      public static final String DESTINATION = "destination";
      public static final String ASYNCOPERATION = "asyncOperation";
      public static final String WSIFOPERATION = "wsifOperation";
  
      public void setDestination(WSIFJMSDestination destination) {
          Trc.entry(this, destination);
          this.destination = destination;
          Trc.exit();
      }
  
      public void setAsyncOperation(String asyncOperation) {
          Trc.entry(this, asyncOperation);
          this.asyncOperation = asyncOperation;
          Trc.exit();
      }
  
      public void setWsifOperation(WSIFOperation wsifOperation) {
          Trc.entry(this, wsifOperation);
          this.wsifOperation = wsifOperation;
          Trc.exit();
      }
  
      public WSIFJMSDestination getDestination() {
          Trc.entry(this);
          Trc.exit(this.destination);
          return this.destination;
      }
  
      public String getAsyncOperation() {
          Trc.entry(this);
          Trc.exit(this.asyncOperation);
          return this.asyncOperation;
      }
  
      public WSIFOperation getWsifOperation() {
          Trc.entry(this);
          Trc.exit(this.wsifOperation);
          return this.wsifOperation;
      }
  
      public void setupMessageContextImpl(
          MessageContext context,
          Call call,
          AxisEngine engine)
          throws AxisFault {
          Trc.entry(this, context, call, engine);
          context.setTransportName("jms");
          if (destination != null)
              context.setProperty(DESTINATION, destination);
          context.setProperty(ASYNCOPERATION, new Boolean(asyncOperation));
          if (wsifOperation != null)
              context.setProperty(WSIFOPERATION, wsifOperation);
          Trc.exit();
      }
  
      public WSIFJmsTransport copy() {
          Trc.entry(this);
          WSIFJmsTransport t = new WSIFJmsTransport();
          t.setDestination(destination);
          t.setAsyncOperation(asyncOperation);
          t.setWsifOperation(wsifOperation);
          if (Trc.ON)
              Trc.exit(t.deep());
          return t;
      }
  
      public String deep() {
          String buff = "";
          try {
              buff = new String(super.toString() + ":\n");
  
              buff += "destination:" + destination;
              buff += "asyncOperation:" + asyncOperation;
              buff += "wsifOperation:" + wsifOperation;
          } catch (Exception e) {
              Trc.exceptionInTrace(e);
          }
          return buff;
      }
  }
  
  
  1.1                  xml-axis-wsif/java/test/proposals/mime/WSIFPort_ApacheAxis.java
  
  Index: WSIFPort_ApacheAxis.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 2002 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 "WSIF" 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) 2001, 2002, International
   * Business Machines, Inc., http://www.apache.org.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  package proposals.mime;
  
  import java.net.MalformedURLException;
  import java.net.URL;
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.List;
  import java.util.Map;
  import java.util.Vector;
  
  import javax.wsdl.Binding;
  import javax.wsdl.BindingFault;
  import javax.wsdl.BindingInput;
  import javax.wsdl.BindingOperation;
  import javax.wsdl.BindingOutput;
  import javax.wsdl.Definition;
  import javax.wsdl.Input;
  import javax.wsdl.Operation;
  import javax.wsdl.Output;
  import javax.wsdl.Port;
  import javax.wsdl.PortType;
  import javax.wsdl.Service;
  import javax.wsdl.extensions.mime.MIMEContent;
  import javax.wsdl.extensions.mime.MIMEMultipartRelated;
  import javax.wsdl.extensions.mime.MIMEPart;
  import javax.wsdl.extensions.soap.SOAPAddress;
  import javax.wsdl.extensions.soap.SOAPBinding;
  import javax.wsdl.extensions.soap.SOAPBody;
  import javax.wsdl.extensions.soap.SOAPFault;
  import javax.wsdl.extensions.soap.SOAPHeader;
  import javax.wsdl.extensions.soap.SOAPOperation;
  import javax.xml.rpc.JAXRPCException;
  
  import org.apache.axis.client.Call;
  import org.apache.axis.client.Transport;
  import org.apache.axis.transport.http.HTTPTransport;
  import org.apache.wsif.WSIFException;
  import org.apache.wsif.WSIFOperation;
  import org.apache.wsif.base.WSIFDefaultPort;
  import org.apache.wsif.logging.Trc;
  import org.apache.wsif.providers.WSIFDynamicTypeMap;
  import org.apache.wsif.util.WSIFProperties;
  import org.apache.wsif.util.jms.WSIFJMSDestination;
  import org.apache.wsif.util.jms.WSIFJMSFinder;
  import org.apache.wsif.wsdl.extensions.jms.JMSAddress;
  import org.apache.wsif.wsdl.extensions.jms.JMSProperty;
  import org.apache.wsif.wsdl.extensions.jms.JMSPropertyValue;
  
  import com.ibm.wsdl.extensions.mime.MIMEConstants;
  
  /**
   * @author Mark Whitlock <wh...@apache.org>
   * @author Ant Elder <an...@uk.ibm.com>
   */
  public class WSIFPort_ApacheAxis extends WSIFDefaultPort {
  
      protected Map operationInstances;
      protected Port port;
      protected Definition definition;
      protected URL url = null;
      protected int transportcode;
      protected Transport st;
      protected List jmsAddressPropVals = null;
      protected Call call;
  
      private static final int HTTP_TRANSPORT = 1;
      private static final int JMS_TRANSPORT = 2;
      private static final int MQJMS_TRANSPORT = 3;
      private static final String CONTEXT_FACTORY = "contextFactory";
      private static final String PROVIDER_URL = "providerURL";
      private static final String FACTORY = "factory";
      private static final String REPLY_QUEUE = "replyQueue";
      private static final String HOST = "host";
      private static final String CHANNEL = "channel";
      private static final String PORT = "port";
      private static final String CCSID = "ccsid";
  
      public WSIFPort_ApacheAxis(
          Definition definition1,
          Service service,
          Port port1,
          WSIFDynamicTypeMap wsifdynamictypemap)
          throws WSIFException {
          Trc.entry(this, definition, service, port1, wsifdynamictypemap);
  
          operationInstances = new HashMap();
          setDefinition(definition1);
          setPort(port1);
  
          JMSAddress jmsaddress =
              (JMSAddress) getExtElem(port1,
                  JMSAddress.class,
                  port1.getExtensibilityElements());
          SOAPAddress soapaddress =
              (SOAPAddress) getExtElem(port1,
                  SOAPAddress.class,
                  port1.getExtensibilityElements());
  
          if (soapaddress != null && jmsaddress != null)
              throw new WSIFException(
                  "Both soap:address and jms:address cannot be specified for port "
                      + port);
  
          if (soapaddress == null && jmsaddress == null)
              throw new WSIFException(
                  "Either soap:address or jms:address must be specified for port "
                      + port);
  
          boolean isNotHTTP = false;
          if (soapaddress != null) {
              String s = soapaddress.getLocationURI();
              try {
                  url = new URL(s);
              } catch (MalformedURLException malformedurlexception) {
                  Trc.exception(malformedurlexception);
                  throw new WSIFException(
                      "could not set SOAP address to " + s,
                      malformedurlexception);
              }
          } else {
              isNotHTTP = true;
              jmsAddressPropVals = jmsaddress.getJMSPropertyValues();
          }
  
          if (url == null && !isNotHTTP)
              throw new WSIFException(
                  "soap:address with location URI is required for " + port1);
          String s1 = null;
          Binding binding = port1.getBinding();
          SOAPBinding soapbinding =
              (SOAPBinding) getExtElem(binding,
                  javax.wsdl.extensions.soap.SOAPBinding.class,
                  binding.getExtensibilityElements());
          if (soapbinding != null) {
              s1 = soapbinding.getStyle();
              if (!"rpc".equals(s1))
                  throw new WSIFException(
                      "unsupported style " + s1 + " for " + soapbinding);
              String s2 = soapbinding.getTransportURI();
              if ("http://schemas.xmlsoap.org/soap/http".equals(s2)) {
                  transportcode = HTTP_TRANSPORT;
                  st = new HTTPTransport();
              } else if ("http://schemas.xmlsoap.org/soap/jms".equals(s2)) {
                  transportcode = JMS_TRANSPORT;
                  st = new WSIFJmsTransport();
                  //	HACK		} else if ("http://schemas.xmlsoap.org/soap/mqjms".equals(s2)) {
                  //	HACK			transportcode = MQJMS_TRANSPORT;
                  //	HACK			st = new MQJMSTransport();
              } else {
                  throw new WSIFException(
                      "unsupported transport " + s2 + " for " + soapbinding);
              }
          }
  
          if (transportcode == JMS_TRANSPORT) {
              WSIFJMSDestination jmsDestination =
                  new WSIFJMSDestination(
                      WSIFJMSFinder.newFinder(jmsaddress, port.getName()),
                      jmsaddress.getJmsProvDestName(),
                      WSIFProperties.getSyncTimeout());
  
              ((WSIFJmsTransport) st).setDestination(jmsDestination);
          }
  
          if (s1 == null)
              s1 = "document";
          PortType porttype = binding.getPortType();
          List list = porttype.getOperations();
          Operation operation;
          WSIFOperation_ApacheAxis wsifoperation_apacheaxis;
          for (Iterator iterator = list.iterator();
              iterator.hasNext();
              setDynamicWSIFOperation(
                  operation.getName(),
                  operation.getInput().getName(),
                  operation.getOutput() == null
                      ? null
                      : operation.getOutput().getName(),
                  wsifoperation_apacheaxis)) {
              operation = (Operation) iterator.next();
              String s3 = operation.getName();
              Input input = operation.getInput();
              Output output = operation.getOutput();
              if (input == null)
                  throw new WSIFException(
                      "missing input message for operation " + s3);
              wsifoperation_apacheaxis =
                  new WSIFOperation_ApacheAxis(
                      this,
                      operation,
                      wsifdynamictypemap);
  
              if (jmsAddressPropVals != null && jmsAddressPropVals.size() > 0) {
                  if (transportcode == JMS_TRANSPORT)
                      wsifoperation_apacheaxis.addInputJmsPropertyValues(
                          jmsAddressPropVals);
                  else
                      throw new WSIFException("jms:propertyValue found in non-jms address");
              }
  
              BindingOperation bindingoperation =
                  binding.getBindingOperation(
                      s3,
                      input.getName(),
                      output == null ? null : output.getName());
              if (bindingoperation == null)
                  throw new WSIFException(
                      "missing required in WSDL 1.1 binding operation for " + s3);
              SOAPOperation soapoperation =
                  (SOAPOperation) getExtElem(bindingoperation,
                      javax.wsdl.extensions.soap.SOAPOperation.class,
                      bindingoperation.getExtensibilityElements());
              if (soapoperation == null)
                  throw new WSIFException(
                      "soapAction must be specified in  required by WSDL 1.1 soap:operation binding for "
                          + bindingoperation);
              String s4 = soapoperation.getSoapActionURI();
              wsifoperation_apacheaxis.setSoapActionURI(s4);
              String s5 = soapoperation.getStyle();
              if (s5 != null && !"rpc".equals(s5))
                  throw new WSIFException(
                      "unsupported style " + s1 + " for operation " + s3);
              if (!"rpc".equals(s1))
                  throw new WSIFException(
                      "default soap style must be rpc if operation "
                          + s3
                          + " binding has not style property");
              BindingInput bindinginput = bindingoperation.getBindingInput();
              List inExtElems = bindinginput.getExtensibilityElements();
              SOAPBody soapbody =
                  (SOAPBody) getExtElem(bindinginput,
                      javax.wsdl.extensions.soap.SOAPBody.class,
                      inExtElems);
              if (soapbody != null) {
              	List list2 = parseSoapBody(wsifoperation_apacheaxis,soapoperation,soapbody,true);
                  if (list2 != null)
                      wsifoperation_apacheaxis.setPartNames(list2);
              } else {
                  MIMEMultipartRelated mimeMultipart =
                      (MIMEMultipartRelated) getExtElem(bindinginput,
                          MIMEMultipartRelated.class,
                          inExtElems);
                  if (mimeMultipart != null)
                      parseMimeMultipart(
                          mimeMultipart,
                          bindingoperation,
                          wsifoperation_apacheaxis,
                          soapoperation,
                          true);
              }
  
              SOAPHeader soapheader =
                  (SOAPHeader) getExtElem(bindinginput,
                      javax.wsdl.extensions.soap.SOAPHeader.class,
                      bindinginput.getExtensibilityElements());
              if (soapheader != null)
                  throw new WSIFException(
                      "not supported input soap:header " + soapheader);
  
              List inJmsProps =
                  getExtElems(
                      bindinginput,
                      JMSProperty.class,
                      bindinginput.getExtensibilityElements());
              if (inJmsProps != null && inJmsProps.size() > 0) {
                  if (st instanceof WSIFJmsTransport)
                      wsifoperation_apacheaxis.setInputJmsProperties(inJmsProps);
                  else
                      throw new WSIFException("jms:properties found in non-jms binding");
              }
  
              List inJmsPropVals =
                  getExtElems(
                      bindinginput,
                      JMSPropertyValue.class,
                      bindinginput.getExtensibilityElements());
              if (inJmsPropVals != null && inJmsPropVals.size() > 0) {
                  if (st instanceof WSIFJmsTransport)
                      wsifoperation_apacheaxis.addInputJmsPropertyValues(
                          inJmsPropVals);
                  else
                      throw new WSIFException("jms:propertyValue found in non-jms binding");
              }
  
              BindingOutput bindingoutput = bindingoperation.getBindingOutput();
              if (bindingoutput != null) {
                  SOAPBody soapbody1 =
                      (SOAPBody) getExtElem(bindingoutput,
                          javax.wsdl.extensions.soap.SOAPBody.class,
                          bindingoutput.getExtensibilityElements());
                  if (soapbody1 != null) {
                      List list3 =
                          parseSoapBody(
                              wsifoperation_apacheaxis,
                              soapoperation,
                              soapbody1,
                              false);
                      if (list3 != null && list3.size() > 0)
                          wsifoperation_apacheaxis.setReturnName(
                              (String) list3.get(0));
                  }
                  soapheader =
                      (SOAPHeader) getExtElem(bindingoutput,
                          javax.wsdl.extensions.soap.SOAPHeader.class,
                          bindingoutput.getExtensibilityElements());
                  if (soapheader != null)
                      throw new WSIFException(
                          "not supported output soap:header " + soapheader);
                  for (Iterator iterator1 =
                      bindingoperation.getBindingFaults().values().iterator();
                      iterator1.hasNext();
                      ) {
                      BindingFault bindingfault = (BindingFault) iterator1.next();
                      SOAPFault soapfault =
                          (SOAPFault) getExtElem(bindingfault,
                              javax.wsdl.extensions.soap.SOAPFault.class,
                              bindingfault.getExtensibilityElements());
                  }
                  List outJmsProps =
                      getExtElems(
                          bindingoutput,
                          JMSProperty.class,
                          bindingoutput.getExtensibilityElements());
                  if (outJmsProps != null && outJmsProps.size() > 0) {
                      if (st instanceof WSIFJmsTransport)
                          wsifoperation_apacheaxis.setOutputJmsProperties(
                              outJmsProps);
                      else
                          throw new WSIFException("jms:properties found in non-jms binding");
                  }
              }
  
          }
  
          if (Trc.ON)
              Trc.exit(deep());
      }
      
      private List parseSoapBody(
          WSIFOperation_ApacheAxis op,
          SOAPOperation soapoperation,
          SOAPBody soapbody,
          boolean isInput)
          throws WSIFException {
  
          Trc.entry(this, op, soapoperation, soapbody, new Boolean(isInput));
  
          if (isInput) {
              String s6 = soapbody.getNamespaceURI();
              op.setInputNamespace(s6);
          }
  
          String s7 = soapbody.getUse();
          if (!"encoded".equals(s7))
              throw new WSIFException(
                  "unsupported use " + s7 + " in " + soapoperation);
  
          if (isInput) {
              List list1 = soapbody.getEncodingStyles();
              if (list1 != null) {
                  list1.size();
                  op.setInputEncodingStyle((String) list1.get(0));
              }
          }
  
          List list2 = soapbody.getParts();
          Trc.exit(list2);
          return list2;
      }
      
      private void parseMimeMultipart(
          MIMEMultipartRelated mimeMultipart,
          BindingOperation bindingoperation,
          WSIFOperation_ApacheAxis wsifoperation_apacheaxis,
          SOAPOperation soapoperation,
          boolean isInput)
          throws WSIFException {
  
          Trc.entry(
              this,
              mimeMultipart,
              bindingoperation,
              wsifoperation_apacheaxis,
              soapoperation);
      	
          Vector mimePartNames = new Vector();
  
          List mimeParts = mimeMultipart.getMIMEParts();
          Iterator mimePartIt = mimeParts.iterator();
          while (mimePartIt.hasNext()) {
              Object nextMimePart = mimePartIt.next();
              if (nextMimePart instanceof MIMEPart) {
                  MIMEPart mimePart = (MIMEPart) nextMimePart;
                  if (!MIMEConstants
                      .NS_URI_MIME
                      .equals(mimePart.getElementType().getNamespaceURI()))
                      throw new WSIFException(
                          "A MIME part in binding operation "
                              + bindingoperation.getName()
                              + " did not have the correct namespace URI of "
                              + MIMEConstants.NS_URI_MIME
                              + ".");
  
                  List mimeContents = mimePart.getExtensibilityElements();
                  Iterator mimeContentIt = mimeContents.iterator();
                  while (mimeContentIt.hasNext()) {
                      Object nextChild = mimeContentIt.next();
                      if (nextChild instanceof MIMEContent) {
                          MIMEContent mimeContent = (MIMEContent) nextChild;
                          if (!MIMEConstants
                              .NS_URI_MIME
                              .equals(
                                  mimePart.getElementType().getNamespaceURI()))
                              throw new WSIFException(
                                  "A MIME part in binding operation "
                                      + bindingoperation.getName()
                                      + " did not have the correct namespace URI of "
                                      + MIMEConstants.NS_URI_MIME
                                      + ".");
  
                          mimePartNames.addElement(mimeContent.getPart());
                      } else if (nextChild instanceof SOAPBody) {
                          List soapPartNames =
                              parseSoapBody(
                                  wsifoperation_apacheaxis,
                                  soapoperation,
                                  (SOAPBody) nextChild,
                                  true);
                          if (soapPartNames != null)
                              mimePartNames.addAll(soapPartNames);
                      }
                  }
              }
          }
          wsifoperation_apacheaxis.setPartNames(mimePartNames);
          
          Trc.exit();
      }
  
      public Definition getDefinition() {
          Trc.entry(this);
          Trc.exit(definition);
          return definition;
      }
  
      public WSIFOperation_ApacheAxis getDynamicWSIFOperation(
          String name,
          String inputName,
          String outputName)
          throws WSIFException {
          Trc.entry(this, name, inputName, outputName);
  
          WSIFOperation_ApacheAxis tempOp =
              (WSIFOperation_ApacheAxis) operationInstances.get(
                  getKey(name, inputName, outputName));
  
          WSIFOperation_ApacheAxis operation = null;
          if (tempOp != null) {
              operation = tempOp.copy();
          }
  
          if (operation == null) {
              BindingOperation bindingOperationModel =
                  port.getBinding().getBindingOperation(
                      name,
                      inputName,
                      outputName);
  
              if (bindingOperationModel != null) {
                  // Only one operation matched in binding so find it in instances
                  // from all the information that is available to us
                  Iterator i = operationInstances.keySet().iterator();
                  while (i.hasNext()) {
                      String key = (String) i.next();
                      if ((outputName != null && key.endsWith(outputName))
                          || outputName == null) {
                          String start =
                              (inputName == null)
                                  ? name + ":"
                                  : name + ":" + inputName;
                          if (key.startsWith(start)) {
                              if (operation != null) {
                                  // Duplicate operation found based on names!
                                  operation = null;
                                  break;
                              }
                              operation =
                                  (
                                      WSIFOperation_ApacheAxis) operationInstances
                                          .get(
                                      key);
                          }
                      }
                  }
              }
          }
  
          Trc.exit(operation);
          return operation;
      }
  
      public URL getEndPoint() {
          Trc.entry(this);
          Trc.exit(url);
          return url;
      }
  
      public Port getPort() {
          Trc.entry(this);
          Trc.exit(port);
          return port;
      }
  
      public Transport getAxisTransport() {
          Trc.entry(this);
          Trc.exit(st);
          return st;
      }
  
      public Call getCall() throws WSIFException {
          Trc.entry(this);
          if (call == null) {
              Transport axistransport = getAxisTransport();
              java.net.URL url = getEndPoint();
              try {
                  if (url != null) {
                      call = new Call(url);
                      if (axistransport != null) {
                          axistransport.setUrl(url.toString());
                      }
                  } else
                      call = new Call(new org.apache.axis.client.Service());
              } catch (JAXRPCException e) {
                  Trc.exception(e);
                  throw new WSIFException(e.toString());
              }
          }
          Trc.exit(call);
          return call;
      }
  
      public void setDefinition(Definition definition1) {
          Trc.entry(this, definition1);
          definition = definition1;
          Trc.exit();
      }
  
      public void setDynamicWSIFOperation(
          String s,
          String s1,
          String s2,
          WSIFOperation_ApacheAxis wsifoperation_apacheaxis) {
          Trc.entry(this, s, s1, s2, wsifoperation_apacheaxis);
          operationInstances.put(getKey(s, s1, s2), wsifoperation_apacheaxis);
          Trc.exit();
      }
  
      public WSIFOperation createOperation(String operationName)
          throws WSIFException {
          Trc.entry(this, operationName);
          WSIFOperation wo = createOperation(operationName, null, null);
          Trc.exit(wo);
          return wo;
      }
  
      public WSIFOperation createOperation(
          String operationName,
          String inputName,
          String outputName)
          throws WSIFException {
          Trc.entry(this, operationName, inputName, outputName);
  
          WSIFOperation_ApacheAxis op =
              getDynamicWSIFOperation(operationName, inputName, outputName);
          if (op == null) {
              throw new WSIFException(
                  "Could not create operation: "
                      + operationName
                      + ":"
                      + inputName
                      + ":"
                      + outputName);
          }
          WSIFOperation wo = op.copy();
          Trc.exit(wo);
          return wo;
      }
  
      public void setEndPoint(URL url1) {
          Trc.entry(this, url1);
          url = url1;
          Trc.exit();
      }
  
      public void setPort(Port port1) {
          Trc.entry(this, port1);
          port = port1;
          Trc.exit();
      }
  
      /**
       * Tests if this port supports asynchronous calls to operations.
       * 
       * @return true if the port is using a JMS transport, otherwise false
       */
      public boolean supportsAsync() {
          Trc.entry(this);
          if (st != null && JMS_TRANSPORT == transportcode) {
              Trc.exit(true);
              return true;
          } else {
              Trc.exit(false);
              return false;
          }
      }
  
      public String deep() {
          String buff = "";
          try {
              buff = new String(super.toString() + ":\n");
              buff += "operationInstances:" + operationInstances;
              buff += " port:" + port;
              buff += " definition:" + definition;
              buff += " url:" + url;
              buff += " transportcode:" + transportcode;
              buff += " st:" + st;
              buff += " jmsAddressPropVals:" + jmsAddressPropVals;
          } catch (Exception e) {
              Trc.exceptionInTrace(e);
          }
          return buff;
      }
  }
  
  
  1.1                  xml-axis-wsif/java/test/proposals/mime/WSIFOperation_ApacheAxis.java
  
  Index: WSIFOperation_ApacheAxis.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 2002 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 "WSIF" 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) 2001, 2002, International
   * Business Machines, Inc., http://www.apache.org.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  package proposals.mime;
  
  import java.io.Serializable;
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.List;
  import java.util.Map;
  import java.util.Vector;
  
  import javax.activation.DataHandler;
  import javax.jms.TextMessage;
  import javax.wsdl.Definition;
  import javax.wsdl.Input;
  import javax.wsdl.Operation;
  import javax.wsdl.Output;
  import javax.wsdl.Part;
  import javax.xml.namespace.QName;
  
  import org.apache.axis.AxisFault;
  import org.apache.axis.Message;
  import org.apache.axis.MessageContext;
  import org.apache.axis.client.Call;
  import org.apache.axis.client.Service;
  import org.apache.axis.client.Transport;
  import org.apache.axis.encoding.TypeMappingRegistry;
  import org.apache.axis.encoding.ser.BeanDeserializerFactory;
  import org.apache.axis.encoding.ser.BeanSerializerFactory;
  import org.apache.axis.encoding.ser.JAFDataHandlerDeserializerFactory;
  import org.apache.axis.encoding.ser.JAFDataHandlerSerializerFactory;
  import org.apache.axis.message.RPCElement;
  import org.apache.axis.message.RPCParam;
  import org.apache.axis.message.SOAPEnvelope;
  import org.apache.axis.message.SOAPFaultElement;
  import org.apache.axis.message.SOAPHeaderElement;
  import org.apache.wsif.WSIFConstants;
  import org.apache.wsif.WSIFCorrelationId;
  import org.apache.wsif.WSIFException;
  import org.apache.wsif.WSIFMessage;
  import org.apache.wsif.WSIFOperation;
  import org.apache.wsif.WSIFResponseHandler;
  import org.apache.wsif.base.WSIFDefaultMessage;
  import org.apache.wsif.base.WSIFDefaultOperation;
  import org.apache.wsif.logging.Trc;
  import org.apache.wsif.providers.WSIFDynamicTypeMap;
  import org.apache.wsif.providers.WSIFDynamicTypeMapping;
  import org.apache.wsif.util.jms.WSIFJMSDestination;
  import org.w3c.dom.Element;
  
  /**
   * @author Mark Whitlock <wh...@apache.org>
   * @author Ant Elder <an...@uk.ibm.com>
   */
  public class WSIFOperation_ApacheAxis
      extends WSIFDefaultOperation
      implements WSIFOperation, Serializable {
      transient protected WSIFPort_ApacheAxis portInstance;
      transient protected Operation operation;
      transient protected Definition definition;
      transient protected List partNames;
      transient protected String names[];
      transient protected Class types[];
      transient protected String inputEncodingStyle;
      transient protected String inputNamespace;
      transient protected String actionUri;
      transient protected Class returnType = null;
      transient protected HashMap outParams;
  
      // for async operation
      transient protected boolean asyncOperation;
      transient protected WSIFCorrelationId asyncRequestID;
  
      // everything other than what is needed to process async response should be transient
      protected WSIFResponseHandler responseHandler;
      protected String returnName = null;
      protected String outputEncodingStyle;
      protected WSIFDynamicTypeMap typeMap;
      protected ArrayList wsdlOutParams;
      
      public WSIFOperation_ApacheAxis(
          WSIFPort_ApacheAxis wsifport_apacheaxis,
          Operation operation1,
          WSIFDynamicTypeMap wsifdynamictypemap)
          throws WSIFException {
          Trc.entry(this, wsifport_apacheaxis, operation1, wsifdynamictypemap);
  
          inputEncodingStyle = "http://schemas.xmlsoap.org/soap/encoding/";
          outputEncodingStyle = "http://schemas.xmlsoap.org/soap/encoding/";
          typeMap = wsifdynamictypemap;
          setDynamicWSIFPort(wsifport_apacheaxis);
          setOperation(operation1);
          setDefinition(wsifport_apacheaxis.getDefinition());
          if (Trc.ON)
              Trc.exit(deep());
      }
  
      /**
       * Create a new copy of this object. This is not a clone, since 
       * it does not copy the referenced objects as well.
       */
      public WSIFOperation_ApacheAxis copy() throws WSIFException {
          Trc.entry(this);
  
          WSIFOperation_ApacheAxis op =
              new WSIFOperation_ApacheAxis(portInstance, operation, typeMap);
  
          op.setSoapActionURI(getSoapActionURI());
          op.setInputNamespace(getInputNamespace());
          op.setInputEncodingStyle(getInputEncodingStyle());
          op.setOutputEncodingStyle(getOutputEncodingStyle());
          op.setPartNames(getPartNames());
          op.setReturnName(getReturnName());
          op.setAsyncOperation(isAsyncOperation());
          op.setResponseHandler(getResponseHandler());
          op.setInputJmsProperties(getInputJmsProperties());
          op.setOutputJmsProperties(getOutputJmsProperties());
          op.setInputJmsPropertyValues(getInputJmsPropertyValues());
  
          if (Trc.ON)
              Trc.exit(op.deep());
          return op;
      }
  
      public Definition getDefinition() {
          Trc.entry(this);
          Trc.exit(definition);
          return definition;
      }
  
      public WSIFPort_ApacheAxis getDynamicWSIFPort() {
          Trc.entry(this);
          Trc.exit(portInstance);
          return portInstance;
      }
  
      public String getInputEncodingStyle() {
          Trc.entry(this);
          Trc.exit(inputEncodingStyle);
          return inputEncodingStyle;
      }
  
      public String getInputNamespace() {
          Trc.entry(this);
          Trc.exit(inputNamespace);
          return inputNamespace;
      }
  
      public String getName() {
          Trc.entry(this);
          String s = operation.getName();
          Trc.exit(s);
          return s;
      }
  
      public Operation getOperation() {
          Trc.entry(this);
          Trc.exit(operation);
          return operation;
      }
  
      public String getOutputEncodingStyle() {
          Trc.entry(this);
          Trc.exit(outputEncodingStyle);
          return outputEncodingStyle;
      }
  
      public List getPartNames() {
          Trc.entry(this);
          Trc.exit(partNames);
          return partNames;
      }
  
      public String getReturnName() {
          Trc.entry(this);
          Trc.exit(returnName);
          return returnName;
      }
  
      public String getSoapActionURI() {
          Trc.entry(this);
          Trc.exit(actionUri);
          return actionUri;
      }
  
      public Transport getTransport() {
          Trc.entry(this);
          Transport t = portInstance.getAxisTransport();
          Trc.exit(t);
          return t;
      }
  
      public WSIFCorrelationId getAsyncRequestID() {
          Trc.entry(this);
          Trc.exit(asyncRequestID);
          return asyncRequestID;
      }
  
      private HashMap getResponseMsgParams() {
          return outParams;
      }
  
      /**
       * Tests if the currently executing request is an asynchronous request.
       * 
       * @return   true if the current request is a asynchronous request,
       *            otherwise false
       */
      public boolean isAsyncOperation() {
          Trc.entry(this);
          Trc.exit(asyncOperation);
          return asyncOperation;
      }
  
      // package visable as it's used by WSIFJmsTransport
      void setAsyncRequestID(WSIFCorrelationId asyncRequestID) {
          Trc.entry(this, asyncRequestID);
          this.asyncRequestID = asyncRequestID;
          Trc.exit();
      }
  
      public void executeInputOnlyOperation(WSIFMessage wsifmessage)
          throws WSIFException {
          Trc.entry(this, wsifmessage);
          setAsyncOperation(false);
          invokeRequestResponseOperation(wsifmessage, null, null);
          Trc.exit();
          return;
      }
  
      /**
       * Performs a request response operation asynchronously.
       * 
       * @param input   input message to send to the operation
       * @return the correlation ID or the request. The correlation ID
       *         is used to associate the request with the WSIFOperation.
       * @exception WSIFException if something goes wrong.
       * @see WSIFOperation#executeRequestResponseAsync(WSIFMessage)
       */
      public WSIFCorrelationId executeRequestResponseAsync(WSIFMessage input)
          throws WSIFException {
          Trc.entry(this, input);
          WSIFCorrelationId id = executeRequestResponseAsync(input, null);
          Trc.exit(id);
          return id;
  
      }
  
      /**
       * Performs a request response operation asynchronously.
       * 
       * @param input   input message to send to the operation
       * @param handler   the response handler that will be notified 
       *        when the asynchronous response becomes available.
       * @return the correlation ID or the request. The correlation ID
       *         is used to associate the request with the WSIFOperation.
       * @exception WSIFException if something goes wrong.
       * @see WSIFOperation#executeRequestResponseAsync(WSIFMessage,WSIFResponseHandler)
       */
      public WSIFCorrelationId executeRequestResponseAsync(
          WSIFMessage input,
          WSIFResponseHandler handler)
          throws WSIFException {
          	
          Trc.entry(this, input, handler);
          close();
  
          if (!portInstance.supportsAsync()) {
              throw new WSIFException("asynchronous operations not available");
          }
  
          setAsyncOperation(true);
          setResponseHandler(handler);
          WSIFJmsTransport transport = (WSIFJmsTransport) getTransport();
          transport.setWsifOperation(this);
          transport.setAsyncOperation("true");
  
          invokeRequestResponseOperation(input, null, null);
  
          transport.setAsyncOperation("false");
          WSIFCorrelationId id = getAsyncRequestID();
          Trc.exit(id);
          return id;
  
      }
  
      /**
       * fireAsyncResponse is called by an AsyncListener when a response
       * has been received for a previous executeRequestResponseAsync call.
       * It passes the response to the executeAsyncResponse method of the
       * associated WSIFResponseHandler.
       * @see WSIFOperation#fireAsyncResponse(Object)
       * @param response   an Object representing the response. The response
       *            should be a JMS TextMessage containging the XML response.
       */
      public void fireAsyncResponse(Object response) throws WSIFException {
          Trc.entry(this, response);
  
          Object result = deserialiseResponseObject(response);
  
          WSIFMessage outMsg = createOutputMessage();
          WSIFMessage faultMsg = createFaultMessage();
          buildResponseMessages(result, outMsg, faultMsg);
  
          getResponseHandler().executeAsyncResponse(outMsg, faultMsg);
  
          Trc.exit(outMsg);
      }
  
      /**
       * Processes the response to an asynchronous request. 
       * This is called for when the asynchronous operation was
       * initiated without a WSIFResponseHandler, that is, by calling
       * the executeRequestResponseAsync(WSIFMessage input) method.
       * 
       * @param response   an Object representing the response.
       * @param output an empty message which will be filled in if
       *        the operation invocation succeeds. If it does not
       *        succeed, the contents of this message are undefined.
       *        (This is a return value of this method.)
       * @param fault an empty message which will be filled in if
       *        the operation invocation fails. If it succeeds, the
       *        contents of this message are undefined. (This is a
       *        return value of this method.)
       * 
       * @return true or false indicating whether a fault message was
       *         generated or not. The truth value indicates whether
       *         the output or fault message has useful information.
       *
       */
      public boolean processAsyncResponse(
          Object response,
          WSIFMessage output,
          WSIFMessage fault)
          throws WSIFException {
          Trc.entry(this, response, output, fault);
  
          Object result = deserialiseResponseObject(response);
          boolean ok = buildResponseMessages(result, output, fault);
  
          Trc.exit( ok ); 
          return ok;
      }
  
      /**
       * This deserialises and unmarshalls the response message.
       * This is copied, with minor changes, from the 2nd half
       * of the Apache Axis Call class invoke method.
       */
      private Object deserialiseResponseObject(Object msg) throws WSIFException {
          if (msg == null) {
              throw new WSIFException("null response to async send");
          }
          if (!(msg instanceof TextMessage)) {
              throw new WSIFException("response not a javax.jms.TextMessage");
          }
  
          try {
              TextMessage m = (TextMessage) msg;
              Message responseMessage = new Message(m.getText());
              responseMessage.setMessageType(Message.RESPONSE);
  
              Service service = new Service();
              MessageContext msgContext = new MessageContext(service.getEngine());
              msgContext.setResponseMessage(responseMessage);
  
              // This registerTypeMapping code is duplicated in prepare
              TypeMappingRegistry tmr = msgContext.getTypeMappingRegistry();
              org.apache.axis.encoding.TypeMapping tm =
                  (org.apache.axis.encoding.TypeMapping) tmr.getTypeMapping(outputEncodingStyle);
              Class objClass;
              String namespaceURI, localPart;
              WSIFDynamicTypeMapping wsifdynamictypemapping;
              for (Iterator iterator = typeMap.iterator(); iterator.hasNext();) {
                  wsifdynamictypemapping = (WSIFDynamicTypeMapping) iterator.next();
                  objClass = wsifdynamictypemapping.getJavaType();
                  namespaceURI = wsifdynamictypemapping.getXmlType().getNamespaceURI();
                  
                  // Filter out XSD and SOAP-ENC types from those we explicitly map.     
                  // Axis already knows how to deal with these; using the BeanSerializer 
                  // would be wrong anyway as they represent simple types and not beans. 
                  if( namespaceURI != null 
                      && !namespaceURI.equals(WSIFConstants.NS_URI_1999_SCHEMA_XSD)
                      && !namespaceURI.equals(WSIFConstants.NS_URI_2000_SCHEMA_XSD) 
                      && !namespaceURI.equals(WSIFConstants.NS_URI_2001_SCHEMA_XSD) 
                      && !namespaceURI.equals(WSIFConstants.NS_URI_SOAP_ENC)) {                
                      localPart = wsifdynamictypemapping.getXmlType().getLocalPart();
                      QName qn = new QName(namespaceURI, localPart);
                      BeanSerializerFactory bsf = new BeanSerializerFactory(objClass, qn);
                      BeanDeserializerFactory bdf = new BeanDeserializerFactory(objClass, qn);
                      tm.register(objClass, qn, bsf, bdf);
                  }
              }
  
              Message resMsg = msgContext.getResponseMessage();
              SOAPEnvelope resEnv = resMsg.getSOAPEnvelope();
  
              Object b = resEnv.getFirstBody();
              if (b instanceof SOAPFaultElement) {
                  return new AxisFault(b.toString());
              }
  
              // RPCElement body = (RPCElement)resEnv.getFirstBody();
              RPCElement body = (RPCElement) b;
  
              Object result = null;
              HashMap outParams;
              Vector resArgs = body.getParams();
  
              if (resArgs != null && resArgs.size() > 0) {
                  RPCParam param = (RPCParam) resArgs.get(0);
                  result = param.getValue();
  
                  if (resArgs.size() > 1) {
                      outParams = new HashMap();
                      for (int i = 1; i < resArgs.size(); i++) {
                          RPCParam p = (RPCParam)resArgs.get( i );
                          outParams.put( p.getName(), p.getValue() );
                      }
                      setResponseMsgParams( outParams );
                  }
              }
              return result;
          } catch (Exception ex) {
          	Trc.exception(ex);
              throw new WSIFException(ex.getMessage());
          }
  
      }
  
      /**
       * Extracts the output or fault message parts from the axis response.
       */
      private boolean buildResponseMessages(
          Object resp,
          WSIFMessage outMsg,
          WSIFMessage faultMsg)
          throws WSIFException {
  
          boolean respOK;
          	
          if (resp instanceof AxisFault) {
              respOK = false;
              if (faultMsg != null) {
                  AxisFault f = (AxisFault) resp;
                  faultMsg.setName(WSIFConstants.SOAP_FAULT_MSG_NAME);
                  faultMsg.setObjectPart(WSIFConstants.SOAP_FAULT_OBJECT, f);
              }
          } else {
              respOK = true;
              populateOutMsgReturnPart( resp, outMsg );
              populateOutMsgParts( outMsg );
          }
  
          return respOK;
      }
      
      /**
       * Populate the outMessage with the response return value.
       */
      private void populateOutMsgReturnPart(Object resp, WSIFMessage outMsg) 
                                        throws WSIFException{
         if (outMsg != null ) {
            if ( returnName != null ) { 
               if ( resp == null ) {
                  throw new WSIFException( 
                     "return value not found in response message" ); 
               } else if ( returnType != null // will be null for async responses
               && !returnType.isPrimitive()
               && !(returnType.isAssignableFrom( resp.getClass() )) ) {
                  throw new WSIFException(
                  "return value "
                  + resp
                  + " has unexpected type "
                  + resp.getClass()
                  + " instead of "
                  + returnType);
               }
               outMsg.setObjectPart( returnName, resp );
            }
         }
      }
  
      /**
       * Populate the outMessage with the expected parts.
       * (this only does the out parameters not the return part)
       */
      private void populateOutMsgParts(WSIFMessage outMsg) 
                                        throws WSIFException{
         if ( outMsg != null ) {
            HashMap respParms = getResponseMsgParams();
            ArrayList wsdlOutParams = getWSDLOutParams();
            if ( respParms != null ) {
             	 String name;
               Object value;
               for (Iterator i = respParms.keySet().iterator(); i.hasNext(); ) {
                  name = (String) i.next();
                  value = respParms.get( name );
                  outMsg.setObjectPart( name, value ); 	
                  wsdlOutParams.remove( name );
               }
            }
            // init any other parts to null
            for (Iterator i=wsdlOutParams.iterator(); i.hasNext(); ) {
               outMsg.setObjectPart( (String) i.next(), null );
            }
         }
      }
      
      public boolean executeRequestResponseOperation(
          WSIFMessage wsifmessage,
          WSIFMessage wsifmessage1,
          WSIFMessage wsifmessage2)
          throws WSIFException {
          	
          Trc.entry(this, wsifmessage, wsifmessage1, wsifmessage2);
          close();
          setAsyncOperation(false);
  
          boolean succ =
              invokeRequestResponseOperation(wsifmessage, wsifmessage1, wsifmessage2);
          Trc.exit(succ);
          return succ;
      }
  
      public boolean invokeRequestResponseOperation(
          WSIFMessage wsifmessage,
          WSIFMessage wsifmessage1,
          WSIFMessage wsifmessage2)
          throws WSIFException {
          Trc.entry(this, wsifmessage, wsifmessage1, wsifmessage2);
  
          Call call = portInstance.getCall();
          Transport axistransport = getTransport();
  
          WSIFJMSDestination dest = null;
          if (axistransport != null) {
              call.setTransport(axistransport);
              if (axistransport instanceof WSIFJmsTransport) {
                  dest = ((WSIFJmsTransport) axistransport).getDestination();
                  dest.setAsyncMode(isAsyncOperation());
              }
          }
  
          if (names == null)
              prepare(call);
  
          if (inJmsPropVals!=null && !inJmsPropVals.isEmpty()) 
            dest.setProperties(inJmsPropVals);
  
          setDestinationContext( dest ); // TODO WSDL props override context???
  
          ArrayList objects = new ArrayList();
          for (int i = 0; i < names.length; i++) {
              Object obj;
          	try {
                 obj = wsifmessage.getObjectPart(names[i]);
          	} catch (WSIFException ex) {
  	        	Trc.exception(ex);
          	   obj = null;
          	}
              if (obj != null) {
                  if (types[i] == null)
                      throw new WSIFException("Cannot map type " + names[i]);
  
                  if (!isPrimitiveOf(obj.getClass(), types[i])
                      && !types[i].isAssignableFrom(obj.getClass())) {
                      throw new WSIFException(
                          "value "
                              + obj
                              + " has unexpected type "
                              + obj.getClass()
                              + " instead of "
                              + types[i]);
                  }
              }
  
              if (inJmsProps.containsKey(names[i]) && dest != null)
                  dest.setProperty((String) (inJmsProps.get(names[i])), obj);
              else
                  objects.add(obj);
          }
  
          setCallContext(call);
          call.setSOAPActionURI( getSoapActionURI() );
  
          Object response;
          boolean respOK = true;
          try {
              String name = operation.getName();
              Object[] objs = objects.toArray();
              Trc.event(
                  this,
                  "Invoking operation ",
                  name,
                  " input namespace ",
                  getInputNamespace(),
                  " parameters ",
                  objs,
                  " call object ",
                  call);
              
              response = call.invoke(getInputNamespace(), name, objs);
          } catch (AxisFault e) {
              Trc.exception(e);
              response = e;
              respOK = false;
          }
  
          Trc.event(this,"Returned from operation, response ",response);
          // setJMSOutPropsInContext( dest ); TODO doesn't work yet
          
          if ( !isAsyncOperation() && returnType != null) {
             Map callParams = call.getOutputParams();
             if ( callParams != null ) {
                HashMap outParams = new HashMap();
                QName qn;
                for (Iterator i= callParams.keySet().iterator(); i.hasNext(); ) {
                   qn = (QName) i.next();              	 
                   outParams.put( qn.getLocalPart(), callParams.get( qn ) );
                }
                setResponseMsgParams( outParams );
             }
             respOK = buildResponseMessages(response, wsifmessage1, wsifmessage2);
          }
  
          Trc.exit(respOK);
          return respOK;
      }
  
      private void prepare(Call call) throws WSIFException {
  
          // This registerTypeMapping code is duplicated in deserialiseResponseObject
          TypeMappingRegistry registry =
              call.getMessageContext().getTypeMappingRegistry();
          Class objClass;
          String namespaceURI, localPart;
          WSIFDynamicTypeMapping wsifdynamictypemapping;
          for (Iterator iterator = typeMap.iterator(); iterator.hasNext();) {
              wsifdynamictypemapping = (WSIFDynamicTypeMapping) iterator.next();
              objClass = wsifdynamictypemapping.getJavaType();
              namespaceURI = wsifdynamictypemapping.getXmlType().getNamespaceURI();
                  
              // Filter out XSD and SOAP-ENC types from those we explicitly map.      
              // Axis already knows how to deal with these; using the BeanSerializer 
              // would be wrong anyway as they represent simple types and not beans. 
              if( namespaceURI != null 
                  && !namespaceURI.equals(WSIFConstants.NS_URI_1999_SCHEMA_XSD)
                  && !namespaceURI.equals(WSIFConstants.NS_URI_2000_SCHEMA_XSD) 
                  && !namespaceURI.equals(WSIFConstants.NS_URI_2001_SCHEMA_XSD) 
                  && !namespaceURI.equals(WSIFConstants.NS_URI_SOAP_ENC)) {            
  
                  localPart = wsifdynamictypemapping.getXmlType().getLocalPart();
                  QName qn = new QName(namespaceURI, localPart);
                  
                  if (DataHandler.class.equals(objClass)) {
                      call.registerTypeMapping(
                          objClass,
                          qn,
                          JAFDataHandlerSerializerFactory.class,
                          JAFDataHandlerDeserializerFactory.class);
                  } else {
                      BeanSerializerFactory bsf =
                          new BeanSerializerFactory(objClass, qn);
                      BeanDeserializerFactory bdf =
                          new BeanDeserializerFactory(objClass, qn);
                      call.registerTypeMapping(objClass, qn, bsf, bdf);
                  }
              }
          }
  
          Input input = operation.getInput();
          if (input != null) {
              Object obj;
              if (partNames != null) {
                  obj = new Vector();
                  Part part1;
                  for (Iterator iterator1 = partNames.iterator();
                      iterator1.hasNext();
                      ((List) (obj)).add(part1)) {
                      String s = (String) iterator1.next();
                      part1 = input.getMessage().getPart(s);
                      if (part1 == null)
                          throw new WSIFException(
                              "no input part named " + s + " for binding operation " + getName());
                  }
  
              } else {
                  obj = input.getMessage().getOrderedParts(null);
              }
              int i = ((List) (obj)).size();
              names = new String[i];
              types = new Class[i];
              for (int j = 0; j < i; j++) {
                  Part part2 = (Part) ((List) (obj)).get(j);
                  names[j] = part2.getName();
                  QName qname1 = part2.getTypeName();
                  if (qname1 == null)
                      throw new WSIFException("part " + names[j] + " must have type name declared");
  
                  javax.xml.rpc.encoding.TypeMapping tm =
                      registry.getTypeMapping("http://schemas.xmlsoap.org/soap/encoding/");
                  if (tm instanceof org.apache.axis.encoding.TypeMapping) {
                      types[j] = ((org.apache.axis.encoding.TypeMapping) tm)
                          .getClassForQName(
                              new QName(qname1.getNamespaceURI(),qname1.getLocalPart()));
                  }
              }
  
          } else {
              names = new String[0];
              types = new Class[0];
          }
          Output output = operation.getOutput();
          if (output != null) {
              Part part = null;
              if (returnName != null) {
                  part = output.getMessage().getPart(returnName);
                  if (part == null)
                      throw new WSIFException(
                          "no output part named " + returnName + " for bining operation " + getName());
              } else {
                  List list = output.getMessage().getOrderedParts(null);
                  if (list.size() > 0) {
                      part = (Part) list.get(0);
                      returnName = part.getName();
                  }
              }
              if (part != null) {
                  QName qname = part.getTypeName();
                  javax.xml.rpc.encoding.TypeMapping tm =
                      registry.getTypeMapping("http://schemas.xmlsoap.org/soap/encoding/");
                  if (tm instanceof org.apache.axis.encoding.TypeMapping) {
                      returnType =
                          ((org.apache.axis.encoding.TypeMapping) tm).getClassForQName(
                              new QName(qname.getNamespaceURI(),qname.getLocalPart()));
                  }
              }
              // setup any output paramter part names defined in the WSDL
              List list = output.getMessage().getOrderedParts(null);
              if ( list.size() > 1 ) {
                 wsdlOutParams = new ArrayList();
                 for (int i=1; i<list.size(); i++) {
                    part = (Part) list.get( i );
                    wsdlOutParams.add( part.getName() );
                 }
                 setWSDLOutParams( wsdlOutParams );
              }
          }
      }
  
      /**
       * Sets the response handler that will be used to
       * process the response to an asynchronous request.
       * @param responseHandler   the responseHandler to use 
       */
      private void setResponseHandler(WSIFResponseHandler responseHandler) {
          this.responseHandler = responseHandler;
      }
  
      /**
       * Gets the response handler that will be used to
       * process the response to a asynchronous request.
       * @return the current response handler.
       * package visable as its used by the transport
       */
      WSIFResponseHandler getResponseHandler() {
          return responseHandler;
      }
  
      private ArrayList getWSDLOutParams() {
      	if ( wsdlOutParams == null ) {
      		wsdlOutParams = new ArrayList();
      	}
          return wsdlOutParams;
      }
  
      private void setWSDLOutParams(ArrayList al) {
          wsdlOutParams = al;
      }
  
      public void setDefinition(Definition definition1) {
          Trc.entry(this, definition1);
          definition = definition1;
          Trc.exit();
      }
  
      public void setDynamicWSIFPort(WSIFPort_ApacheAxis wsifport_apacheaxis) {
          Trc.entry(this, wsifport_apacheaxis);
          portInstance = wsifport_apacheaxis;
          Trc.exit();
      }
  
      public void setInputEncodingStyle(String s) {
          Trc.entry(this, s);
          inputEncodingStyle = s;
          Trc.exit();
      }
  
      public void setInputNamespace(String s) {
          Trc.entry(this, s);
          inputNamespace = s;
          Trc.exit();
      }
  
      public void setOperation(Operation operation1) {
          Trc.entry(this, operation1);
          operation = operation1;
          Trc.exit();
      }
  
      public void setOutputEncodingStyle(String s) {
          Trc.entry(this, s);
          outputEncodingStyle = s;
          Trc.exit();
      }
  
      public void setPartNames(List list) {
          Trc.entry(this, list);
          partNames = list;
          Trc.exit();
      }
  
      public void setReturnName(String s) {
          Trc.entry(this, s);
          returnName = s;
          Trc.exit();
      }
  
      public void setSoapActionURI(String s) {
          Trc.entry(this, s);
          actionUri = s;
          Trc.exit();
      }
  
      private void setResponseMsgParams(HashMap hm) {
          outParams = hm;
      }
  
      /**
       * Sets if the currently executing request is an asynchronous request.
       * 
       * @param b   true if the current request is a asynchronous request,
       *            otherwise false
       */
      private void setAsyncOperation(boolean b) {
          asyncOperation = b;
      }
  
      /**
       * Gets the target namespace URI of this WSIFOperation 
       * 
       * @return the target namespace URI
       */
      public String getTargetNamespaceURI() {
          Trc.entry(this);
          Definition d = getDefinition();
          String s = (d == null) ? "" : d.getTargetNamespace();
          Trc.exit(s);
          return s;
      }
  
      /**
       * Creates a new input WSIFMessage. This overrides the 
       * WSIFDefaultOperation method to enable the use of 
       * compiled WSIFMessages by using a WSIFMessageFactory
       * to create the message.
       * 
       * @param name   the name of the message
       * @return a WSIFMessage instance
       * @see WSIFOperation#createInputMessage(String)
       */
  // defect 131672 and disable compiled msg support for now
  //    public WSIFMessage createInputMessage(String name) {
  //        Tr.entry(this, name);
  //        Definition d = getDefinition();
  //        String ns = (d == null) ? "" : d.getTargetNamespace();
  //        WSIFMessageFactory mf = WSIFServiceImpl.getMessageFactory();
  //        WSIFMessage msg = mf.createMessage(ns, name + "Message");
  //        if (msg != null)
  //            msg.setName(name);
  //        Tr.exit(msg);
  //        return msg;
  //   }
  
      /**
       * Creates a new output WSIFMessage. This overrides the 
       * WSIFDefaultOperation method to enable the use of 
       * compiled WSIFMessages by using a WSIFMessageFactory
       * to create the message.
       * 
       * @param name   the name of the message
       * @return a WSIFMessage instance
       * @see WSIFOperation#createInputMessage(String)
       */
  // defect 131672 and disable compiled msg support for now
  //    public WSIFMessage createOutputMessage(String name) {
  //        Tr.entry(this, name);
  //        Definition d = getDefinition();
  //        String ns = (d == null) ? "" : d.getTargetNamespace();
  //        WSIFMessageFactory mf = WSIFServiceImpl.getMessageFactory();
  //        WSIFMessage msg = mf.createMessage(ns, name + "Message");
  //        if (msg != null)
  //            msg.setName(name);
  //        Tr.exit(msg);
  //        return msg;
  //    }
  
      /**
       * This sets up the output JMS property values in the context
       */
      private void setJMSOutPropsInContext(WSIFJMSDestination dest) throws WSIFException {
         if ( dest == null ) {
            return;
         }
         HashMap props = dest.getProperties();
         if ( props != null ) {
            if ( context == null ) {
               context = new WSIFDefaultMessage();
            }
            context.setParts( props );
         }
      }
      
      /**
       * This sets up any context JMS property values in the Destination
       */
      private void setDestinationContext(WSIFJMSDestination dest) {
         if ( context == null 
         || dest == null ) {
            return;
         }
         String partName;
         HashMap jmsProps = new HashMap();
         for (Iterator i = context.getPartNames(); i.hasNext(); ) {
            partName = (String)i.next();
            if ( partName.startsWith( WSIFConstants.CONTEXT_JMS_PREFIX ) ) {
               try {
                  jmsProps.put( partName.substring( WSIFConstants.CONTEXT_JMS_PREFIX.length() ), 
                                context.getObjectPart( partName ) );
               } catch (WSIFException ex) {
  	        	Trc.ignoredException(ex);
               }
            } 
         }
         if ( jmsProps.size() > 0 ) {
            dest.setProperties( jmsProps );
         }
      }
  
      /**
       * This sets up the context headers in the axis 
       * Call object prior to invoke method being issued.
       */
      private void setCallContext(Call call) {
          Object o;
          String name;
          if (context == null) {
              return;
          }
          name = WSIFConstants.CONTEXT_HTTP_USER;
          try {
             o = context.getObjectPart( name );
             if ( o instanceof String ) {
                addHTTPHeader( call, name, (String)o );
             }           	
          } catch (WSIFException ex) {
          	Trc.ignoredException(ex);
          }      
  
          name = WSIFConstants.CONTEXT_HTTP_PSWD;
          try {
             o = context.getObjectPart( name );
             if ( o instanceof String ) {
                addHTTPHeader( call, name, (String)o );
             }           	
          } catch (WSIFException ex) {
          	Trc.ignoredException(ex);
          }      
  
          try {
             name = WSIFConstants.CONTEXT_SOAP_HEADERS;
             o = context.getObjectPart( name );
             if ( o instanceof List ) {
                addSOAPHeader( call, name, (List)o );           	
             }           	
          } catch (WSIFException ex) {
          	Trc.ignoredException(ex);
          }      
      }
  
      /**
       * Sets the SOAP headers in the message context.
       */
      private void addSOAPHeader(Call call, String name, List soapHeaders) {
          for (Iterator i = soapHeaders.iterator(); i.hasNext();) {
              Object o = i.next();
              if (o instanceof Element) {
                  call.addHeader(new SOAPHeaderElement((Element) o));
              }
          }
      }
  
      /**
       * Sets the HTTP header value in the message context.
       * How these are used depends on the underlying transport, 
       * eg. org.apache.axis.transport.http.HTTPSender
       * will use the 'user.id' and 'user.password' headers
       * for HTTP basic authentication..  
       */
      private void addHTTPHeader(Call call, String name, String value) {
          if (name.equals(WSIFConstants.CONTEXT_HTTP_USER)) {
              call.setProperty(Call.USERNAME_PROPERTY, value);
          } else if (name.equals(WSIFConstants.CONTEXT_HTTP_PSWD)) {
              call.setProperty(Call.PASSWORD_PROPERTY, value);
          }
      }
  
      /**
       * Returns true if primitive is the equivalent primitive class of clazz.
       * Why doesn't java provide this function?
       */
      private static boolean isPrimitiveOf(Class clazz, Class primitive) {
          if ((primitive.equals(boolean.class) && Boolean.class.isAssignableFrom(clazz))
              || (primitive.equals(char.class) && Character.class.isAssignableFrom(clazz))
              || (primitive.equals(byte.class) && Byte.class.isAssignableFrom(clazz))
              || (primitive.equals(short.class) && Short.class.isAssignableFrom(clazz))
              || (primitive.equals(int.class) && Integer.class.isAssignableFrom(clazz))
              || (primitive.equals(long.class) && Long.class.isAssignableFrom(clazz))
              || (primitive.equals(float.class) && Float.class.isAssignableFrom(clazz))
              || (primitive.equals(double.class) && Double.class.isAssignableFrom(clazz)))
              return true;
          else
              return false;
      }
  
      public String deep() {
          String buff = "";
          try {
              buff = new String(super.toString() + ":\n");
  
              buff += "portInstance:" + portInstance;
              buff += " operation:" + Trc.brief(operation);
              buff += " definition:" + Trc.brief(definition);
              buff += " partNames:" + partNames;
              buff += " names:" + names;
              buff += " types:" + types;
              buff += " inputEncodingStyle:" + inputEncodingStyle;
              buff += " inputNamespace:" + inputNamespace;
              buff += " actionUri:" + actionUri;
              buff += " inJmsProps:" + inJmsProps;
              buff += " outJmsProps:" + outJmsProps;
              buff += " inJmsPropVals:" + inJmsPropVals;
              buff += " context:" + context;
              buff += " returnType:" + returnType;
              buff += " asyncOperation:" + asyncOperation;
              buff += " asyncRequestID:" + asyncRequestID;
              buff += " responseHandler:" + responseHandler;
              buff += " returnName:" + returnName;
              buff += " wsdlOutParams:" + wsdlOutParams;
              buff += " outParams:" + outParams;
              buff += " outputEncodingStyle:" + outputEncodingStyle;
              buff += " typeMap:" + typeMap;
          } catch (Exception e) {
              Trc.exceptionInTrace(e);
          }
  
          return buff;
      }
  }
  
  
  1.5       +46 -0     xml-axis-wsif/java/test/inout/wsifservice/Inout.wsdl
  
  Index: Inout.wsdl
  ===================================================================
  RCS file: /home/cvs/xml-axis-wsif/java/test/inout/wsifservice/Inout.wsdl,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- Inout.wsdl	25 Jun 2002 09:38:43 -0000	1.4
  +++ Inout.wsdl	3 Oct 2002 09:20:46 -0000	1.5
  @@ -9,6 +9,7 @@
                xmlns:jms="http://schemas.xmlsoap.org/wsdl/jms/"
                xmlns:format="http://schemas.xmlsoap.org/wsdl/formatbinding/"
                xmlns:java="http://schemas.xmlsoap.org/wsdl/java/"
  +             xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
                xmlns="http://schemas.xmlsoap.org/wsdl/">
   
     <!-- type defs -->
  @@ -121,6 +122,14 @@
       <part name="type" type="xsd:string"/>
     </message>
   
  +  <message name="FileToStringRequestMessage">
  +    <part name="file" type="typeions:datahandler"/>
  +  </message>
  +
  +  <message name="FileToStringResponseMessage">
  +    <part name="buff" type="xsd:string"/>
  +  </message>
  +
     <!-- port type declns -->
     <portType name="Inout">
       <operation name="addEntry">
  @@ -185,6 +194,12 @@
         <output name="WhoamiAddressResponse" 
                 message="tns:WhoamiAddressResponseMessage"/>
       </operation>
  +    <operation name="fileToString">
  +      <input name="FileToStringRequest" 
  +             message="tns:FileToStringRequestMessage"/>
  +      <output name="FileToStringResponse" 
  +              message="tns:FileToStringResponseMessage"/>
  +    </operation>
     </portType>
   
     <portType name="InoutDoc">
  @@ -359,6 +374,24 @@
                      encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
         </output>
       </operation>
  +    <operation name="fileToString">
  +      <soap:operation soapAction=""/>
  +      <input name="FileToStringRequest">
  +        <mime:multipartRelated>
  +          <mime:part>
  +            <mime:content part="file" type="text/html"/>
  +            <soap:body use="encoded"
  +                       namespace="http://wsifservice.inout/"
  +                       encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
  +          </mime:part>
  +        </mime:multipartRelated> 
  +      </input>
  +      <output name="FileToStringResponse">
  +        <soap:body use="encoded"
  +                   namespace="http://wsifservice.inout/"
  +                   encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
  +      </output>
  +    </operation>
     </binding>
   
     <binding name="SOAPJmsBinding" type="tns:Inout">
  @@ -492,6 +525,19 @@
                      encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
         </input>
         <output name="WhoamiAddressResponse">
  +        <soap:body use="encoded"
  +                   namespace="http://wsifservice.inout/"
  +                   encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
  +      </output>
  +    </operation>
  +    <operation name="fileToString">
  +      <soap:operation soapAction=""/>
  +      <input name="FileToStringRequest">
  +        <soap:body use="encoded"
  +                   namespace="http://wsifservice.inout/"
  +                   encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
  +      </input>
  +      <output name="FileToStringResponse">
           <soap:body use="encoded"
                      namespace="http://wsifservice.inout/"
                      encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
  
  
  
  1.3       +7 -1      xml-axis-wsif/java/test/inout/wsifservice/DeploymentDescriptor.xml
  
  Index: DeploymentDescriptor.xml
  ===================================================================
  RCS file: /home/cvs/xml-axis-wsif/java/test/inout/wsifservice/DeploymentDescriptor.xml,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- DeploymentDescriptor.xml	14 Jun 2002 14:05:51 -0000	1.2
  +++ DeploymentDescriptor.xml	3 Oct 2002 09:20:46 -0000	1.3
  @@ -2,7 +2,7 @@
                id="http://wsifservice.inout/">
     <isd:provider type="java"
                   scope="Application"
  -                methods="addEntry getAddressFromName addNumbers getDate whoami">
  +                methods="addEntry getAddressFromName addNumbers getDate whoami fileToString">
       <isd:java class="inout.wsiftypes.InoutImpl" static="false"/>
     </isd:provider>
   
  @@ -33,5 +33,11 @@
             javaType="[I" 
             java2XMLClassName="org.apache.soap.encoding.soapenc.ArraySerializer" 
             xml2JavaClassName="org.apache.soap.encoding.soapenc.ArraySerializer" /> 
  +    <isd:map encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" 
  +          xmlns:x="http://wsiftypes.inout/" 
  +          qname="x:datahandler" 
  +          javaType="javax.activation.DataHandler" 
  +          java2XMLClassName="org.apache.soap.encoding.soapenc.MimePartSerializer" 
  +          xml2JavaClassName="org.apache.soap.encoding.soapenc.MimePartSerializer" /> 
     </isd:mappings>    
   </isd:service>
  
  
  
  1.2       +19 -3     xml-axis-wsif/java/test/inout/wsiftypes/InoutImpl.java
  
  Index: InoutImpl.java
  ===================================================================
  RCS file: /home/cvs/xml-axis-wsif/java/test/inout/wsiftypes/InoutImpl.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- InoutImpl.java	6 Jun 2002 08:28:56 -0000	1.1
  +++ InoutImpl.java	3 Oct 2002 09:20:46 -0000	1.2
  @@ -57,15 +57,19 @@
   
   package inout.wsiftypes;
   
  +import inout.wsifservice.Inout;
  +import java.io.IOException;
  +import java.io.InputStream;
   import java.util.Date;
   import java.util.Hashtable;
   import java.util.Iterator;
   
  +import javax.activation.DataHandler;
  +
  +import util.AddressUtility;
  +
   import addressbook.wsiftypes.Address;
   import addressbook.wsiftypes.Phone;
  -import inout.wsifservice.Inout;
  -import inout.wsiftypes.Mutablestring;
  -import util.AddressUtility;
   
   /**
    * Inout service used by InoutTest for various miscelleanous tests.
  @@ -171,5 +175,17 @@
       }
       public String whoami(Address a) {
           return new String("Address");
  +    }
  +
  +    public String fileToString(DataHandler dh) {
  +        try {
  +            InputStream is = dh.getInputStream();
  +            byte[] bBuff = new byte[is.available()];
  +            is.read(bBuff);
  +            String sBuff = new String(bBuff);
  +            return sBuff;
  +        } catch (IOException ioe) {
  +            return null;
  +        }
       }
   }