dims        2002/12/16 16:01:35

  Modified:    java/src/org/apache/axis/client AxisClientProxy.java
                        Call.java Service.java
  Added:       java/test/wsdl/jaxrpcdynproxy AddressInOut.wsdl
                        AddressSoapBindingImpl.java
                        JAXRPCDynProxyTestCase.java build.xml
  Log:
  Fix for Bug 15183 - [Patch] Dynamic proxy client does not handle inout parameters 
(handlers)
  from [EMAIL PROTECTED] (Cédric Chabanois)
  
  Revision  Changes    Path
  1.4       +123 -4    xml-axis/java/src/org/apache/axis/client/AxisClientProxy.java
  
  Index: AxisClientProxy.java
  ===================================================================
  RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/client/AxisClientProxy.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- AxisClientProxy.java      29 Nov 2002 17:17:10 -0000      1.3
  +++ AxisClientProxy.java      17 Dec 2002 00:01:35 -0000      1.4
  @@ -57,6 +57,15 @@
   
   import java.lang.reflect.InvocationHandler;
   import java.lang.reflect.Method;
  +import java.util.Map;
  +import java.util.Vector;
  +
  +import javax.xml.namespace.QName;
  +import javax.xml.rpc.holders.Holder;
  +
  +import org.apache.axis.description.OperationDesc;
  +import org.apache.axis.description.ParameterDesc;
  +import org.apache.axis.utils.JavaUtils;
   
   /**
    * Very simple dynamic proxy InvocationHandler class.  This class is
  @@ -65,20 +74,97 @@
    * a SOAP request.
    *
    * @author Glen Daniels ([EMAIL PROTECTED])
  + * @author Cédric Chabanois ([EMAIL PROTECTED])
    */
   public class AxisClientProxy implements InvocationHandler {
  -    Call call;
  +
  +    private Call call;
  +    private QName portName;
   
       /**
        * Constructor - package access only (should only really get used
        * in Service.getPort(endpoint, proxyClass).
  +     * Call can be pre-filled from wsdl
        */
  -    AxisClientProxy(Call call)
  +    AxisClientProxy(Call call, QName portName)
       {
           this.call = call;
  +        this.portName = portName; // can be null
  +    }
  +
  +
  +    /**
  +     * Parameters for invoke method are not the same as parameter for Call 
  +     * instance : 
  +     * - Holders must be converted to their mapped java types
  +     * - only in and inout parameters must be present in call parameters
  +     * 
  +     * @param proxyParams proxyParameters
  +     * @return Object[]   Call parameters
  +     * @throws JavaUtils.HolderException
  +     */
  +    private Object[] proxyParams2CallParams(Object[] proxyParams)
  +        throws JavaUtils.HolderException
  +    {
  +        OperationDesc operationDesc = call.getOperation();
  +        if (operationDesc == null)
  +        {
  +            // we don't know which parameters are IN, OUT or INOUT
  +            // let's suppose they are all in
  +            return proxyParams; 
  +        }
  +        
  +        Vector paramsCall = new Vector();
  +        for (int i = 0; i < proxyParams.length;i++)
  +        {
  +            Object param = proxyParams[i];
  +            ParameterDesc paramDesc = operationDesc.getParameter(i);            
  +            
  +            if (paramDesc.getMode() == ParameterDesc.INOUT) {
  +                paramsCall.add(JavaUtils.getHolderValue((Holder)param));
  +            } 
  +            else
  +            if (paramDesc.getMode() == ParameterDesc.IN) {
  +                paramsCall.add(param);
  +            }
  +        }
  +        return paramsCall.toArray();
       }
   
       /**
  +     * copy in/out and out parameters (Holder parameters) back to proxyParams 
  +     * 
  +     * @param proxyParams proxyParameters
  +     */
  +    private void callOutputParams2proxyParams(Object[] proxyParams)
  +        throws JavaUtils.HolderException
  +    {
  +        OperationDesc operationDesc = call.getOperation();
  +        if (operationDesc == null)
  +        {
  +            // we don't know which parameters are IN, OUT or INOUT
  +            // let's suppose they are all in
  +            return;
  +        }
  +        
  +        Map outputParams = call.getOutputParams();
  +       
  +        for (int i = 0; i < operationDesc.getNumParams();i++)
  +        {
  +            Object param = proxyParams[i];
  +            ParameterDesc paramDesc = operationDesc.getParameter(i);
  +            if ((paramDesc.getMode() == ParameterDesc.INOUT) ||
  +                (paramDesc.getMode() == ParameterDesc.OUT)) {
  +                             
  +                  JavaUtils.setHolderValue((Holder)param,
  +                      outputParams.get(paramDesc.getQName()));
  +            }
  +        }
  +    }
  +
  +
  +
  +    /**
        * Handle a method invocation.
        */
       public Object invoke(Object o, Method method, Object[] objects)
  @@ -88,8 +174,41 @@
               return null;
           }
           else {
  -            call.setOperation(call.getPortName(), method.getName());
  -            return call.invoke(objects);
  +          Object outValue;
  +          Object[] paramsCall;
  +          
  +          if ((call.getTargetEndpointAddress() != null) &&
  +              (call.getPortName() != null)) {
  +              // call object has been prefilled : targetEndPoint and portname
  +              // are already set. We complete it with method informations
  +              call.setOperation(method.getName());
  +              paramsCall = proxyParams2CallParams(objects);
  +              outValue = call.invoke(paramsCall);
  +          }
  +          else if (portName != null)
  +          {
  +              // we only know the portName. Try to complete this information
  +              // from wsdl if available
  +              call.setOperation(portName,method.getName());
  +              paramsCall = proxyParams2CallParams(objects);
  +              outValue = call.invoke(paramsCall);
  +          }
  +          else
  +          {
  +              // we don't even know the portName (we don't have wsdl)
  +              paramsCall = objects;
  +              outValue = call.invoke(method.getName(), paramsCall);
  +          }
  +          callOutputParams2proxyParams(objects);
  +          return outValue;
           }
  +    }
  +    
  +    /**
  +     * Returns the current call 
  +     * @return call
  +     */ 
  +    public Call getCall(){
  +        return call;
       }
   }
  
  
  
  1.195     +116 -23   xml-axis/java/src/org/apache/axis/client/Call.java
  
  Index: Call.java
  ===================================================================
  RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/client/Call.java,v
  retrieving revision 1.194
  retrieving revision 1.195
  diff -u -r1.194 -r1.195
  --- Call.java 11 Dec 2002 22:38:09 -0000      1.194
  +++ Call.java 17 Dec 2002 00:01:35 -0000      1.195
  @@ -2,7 +2,7 @@
   * The Apache Software License, Version 1.1
   *
   *
  - * Copyright (c) 2001 The Apache Software Foundation.  All rights
  +* Copyright (c) 2001 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
  @@ -1146,14 +1146,27 @@
           operationName = new QName(opName);
       }
   
  -    public void setOperation(QName portName, String opName) {
  +    /**
  +     * Prefill as much info from the WSDL as it can.  
  +     * Right now it's SOAPAction, operation qname, parameter types 
  +     * and return type of the Web Service.
  +     *
  +     * This methods considers that port name and target endpoint address have
  +     * already been set. This is useful when you want to use the same Call 
  +     * instance for several calls on the same Port
  +     *
  +     * Note: Not part of JAX-RPC specification.
  +     * 
  +     * @param  portName        PortName in the WSDL doc to search for
  +     * @param  opName          Operation(method) that's going to be invoked
  +     */     
  +    public void setOperation(String opName) {
           if ( service == null )
               throw new JAXRPCException( Messages.getMessage("noService04") );
   
  -        // Make sure we're making a fresh start.
  -        this.setPortName( portName );
  +        // remove all settings concerning an operation
  +        // leave portName and targetEndPoint as they are
           this.setOperationName( opName );
  -        this.setTargetEndpointAddress( (URL) null );
           this.setEncodingStyle( null );
           this.setReturnType( null );
           this.removeAllParameters();
  @@ -1188,26 +1201,9 @@
               throw new JAXRPCException( Messages.getMessage("noOperation01",
                                                              opName) );
   
  -        // Get the URL
  -        ////////////////////////////////////////////////////////////////////
  -        List list = port.getExtensibilityElements();
  -        for ( int i = 0 ; list != null && i < list.size() ; i++ ) {
  -            Object obj = list.get(i);
  -            if ( obj instanceof SOAPAddress ) {
  -                try {
  -                    SOAPAddress addr = (SOAPAddress) obj ;
  -                    URL         url  = new URL(addr.getLocationURI());
  -                    this.setTargetEndpointAddress(url);
  -                }
  -                catch(Exception exp) {
  -                    throw new JAXRPCException(
  -                            Messages.getMessage("cantSetURI00", "" + exp) );
  -                }
  -            }
  -        }
  -
           // Get the SOAPAction
           ////////////////////////////////////////////////////////////////////
  +        List list = port.getExtensibilityElements();
           String opStyle = null;
           BindingOperation bop = binding.getBindingOperation(opName,
                                                              null, null);
  @@ -1360,6 +1356,98 @@
           // need to be specified with addParameter calls.
           parmAndRetReq = false;
           return;
  +     
  +    }
  +
  +
  +    /**
  +     * prefill as much info from the WSDL as it can.  
  +     * Right now it's target URL, SOAPAction, Parameter types,
  +     * and return type of the Web Service.
  +     * 
  +     * If wsdl is not present, this function set port name and operation name
  +     * and does not modify target endpoint address.
  +     *
  +     * Note: Not part of JAX-RPC specification.
  +     * 
  +     * @param  portName        PortName in the WSDL doc to search for
  +     * @param  opName          Operation(method) that's going to be invoked
  +     */
  +    public void setOperation(QName portName, String opName) {
  +        if ( service == null )
  +            throw new JAXRPCException( Messages.getMessage("noService04") );
  +
  +        // Make sure we're making a fresh start.
  +        this.setPortName( portName );
  +        this.setOperationName( opName );
  +        this.setEncodingStyle( null );
  +        this.setReturnType( null );
  +        this.removeAllParameters();
  +
  +        javax.wsdl.Service wsdlService = service.getWSDLService();
  +        // Nothing to do is the WSDL is not already set.
  +        if(wsdlService == null)
  +            return;
  +
  +        // we reinitialize target endpoint only if we have wsdl
  +        this.setTargetEndpointAddress( (URL) null );
  +
  +        Port port = wsdlService.getPort( portName.getLocalPart() );
  +        if ( port == null )
  +            throw new JAXRPCException( Messages.getMessage("noPort00", "" +
  +                                                           portName) );
  +
  +        Binding   binding  = port.getBinding();
  +        PortType  portType = binding.getPortType();
  +        if ( portType == null )
  +            throw new JAXRPCException( Messages.getMessage("noPortType00", "" +
  +                                                           portName) );
  +
  +        // Get the URL
  +        ////////////////////////////////////////////////////////////////////
  +        List list = port.getExtensibilityElements();
  +        for ( int i = 0 ; list != null && i < list.size() ; i++ ) {
  +            Object obj = list.get(i);
  +            if ( obj instanceof SOAPAddress ) {
  +                try {
  +                    SOAPAddress addr = (SOAPAddress) obj ;
  +                    URL         url  = new URL(addr.getLocationURI());
  +                    this.setTargetEndpointAddress(url);
  +                }
  +                catch(Exception exp) {
  +                    throw new JAXRPCException(
  +                            Messages.getMessage("cantSetURI00", "" + exp) );
  +                }
  +            }
  +        }
  +
  +        // Get the SOAPAction
  +        ////////////////////////////////////////////////////////////////////
  +        String opStyle = null;
  +        BindingOperation bop = binding.getBindingOperation(opName,
  +                                                           null, null);
  +        if ( bop == null )
  +            throw new JAXRPCException( Messages.getMessage("noOperation02",
  +                                                            opName ));
  +        list = bop.getExtensibilityElements();
  +        for ( int i = 0 ; list != null && i < list.size() ; i++ ) {
  +            Object obj = list.get(i);
  +            if ( obj instanceof SOAPOperation ) {
  +                SOAPOperation sop    = (SOAPOperation) obj ;
  +                opStyle = ((SOAPOperation) obj).getStyle();
  +                String        action = sop.getSoapActionURI();
  +                if ( action != null ) {
  +                    setUseSOAPAction(true);
  +                    setSOAPActionURI(action);
  +                }
  +                else {
  +                    setUseSOAPAction(false);
  +                    setSOAPActionURI(null);
  +                }
  +                break ;
  +            }
  +        }
  +        setOperation(opName);
       }
   
       /**
  @@ -2539,6 +2627,11 @@
       public void setOperation(OperationDesc operation) {
           this.operation = operation;
           operationSetManually = true;
  +    }
  +    
  +    public OperationDesc getOperation()
  +    {
  +        return operation;  
       }
   
       public void clearOperation() {
  
  
  
  1.83      +1 -1      xml-axis/java/src/org/apache/axis/client/Service.java
  
  Index: Service.java
  ===================================================================
  RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/client/Service.java,v
  retrieving revision 1.82
  retrieving revision 1.83
  diff -u -r1.82 -r1.83
  --- Service.java      19 Nov 2002 22:47:01 -0000      1.82
  +++ Service.java      17 Dec 2002 00:01:35 -0000      1.83
  @@ -437,7 +437,7 @@
                       Thread.currentThread().getContextClassLoader();
               return (Remote)Proxy.newProxyInstance(classLoader,
                       new Class[] { proxyInterface, javax.xml.rpc.Stub.class },
  -                    new AxisClientProxy(call));
  +                    new AxisClientProxy(call, portName));
           } catch (Exception e) {
               throw new ServiceException(e.toString());
           }
  
  
  
  1.1                  xml-axis/java/test/wsdl/jaxrpcdynproxy/AddressInOut.wsdl
  
  Index: AddressInOut.wsdl
  ===================================================================
  <?xml version="1.0" encoding="UTF-8"?>
  <wsdl:definitions targetNamespace="http://jaxrpcdynproxy.wsdl.test"; 
xmlns="http://schemas.xmlsoap.org/wsdl/"; 
xmlns:apachesoap="http://xml.apache.org/xml-soap"; 
xmlns:impl="http://jaxrpcdynproxy.wsdl.test"; 
xmlns:intf="http://jaxrpcdynproxy.wsdl.test"; 
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"; 
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"; 
xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/"; 
xmlns:xsd="http://www.w3.org/2001/XMLSchema";>
   <wsdl:types>
    <schema targetNamespace="http://jaxrpcdynproxy.wsdl.test"; 
xmlns="http://www.w3.org/2001/XMLSchema";>
     <import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
     <complexType name="AddressBean">
      <sequence>
       <element name="street" nillable="true" type="xsd:string"/>
       <element name="postcode" type="xsd:int"/>
      </sequence>
     </complexType>
     <element name="AddressBean" nillable="true" type="impl:AddressBean"/>
    </schema>
    <schema targetNamespace="http://www.w3.org/2001/XMLSchema"; 
xmlns="http://www.w3.org/2001/XMLSchema";>
     <import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
     <element name="int" type="xsd:int"/>
     <element name="string" type="xsd:string"/>
    </schema>
   </wsdl:types>
  
     <wsdl:message name="updateAddressRequest">
  
        <wsdl:part name="in0" type="intf:AddressBean"/>
  
        <wsdl:part name="in1" type="xsd:int"/>
  
     </wsdl:message>
  
     <wsdl:message name="updateAddressResponse">
        <wsdl:part name="in0" type="intf:AddressBean"/>
  
        <wsdl:part name="return" type="xsd:string"/>
  
     </wsdl:message>
  
     <wsdl:portType name="AddressService">
  
        <wsdl:operation name="updateAddress" parameterOrder="in0 in1">
  
           <wsdl:input message="intf:updateAddressRequest" 
name="updateAddressRequest"/>
  
           <wsdl:output message="intf:updateAddressResponse" 
name="updateAddressResponse"/>
  
        </wsdl:operation>
  
     </wsdl:portType>
  
     <wsdl:binding name="AddressSoapBinding" type="intf:AddressService">
  
        <wsdlsoap:binding style="rpc" 
transport="http://schemas.xmlsoap.org/soap/http"/>
  
        <wsdl:operation name="updateAddress">
  
           <wsdlsoap:operation soapAction=""/>
  
           <wsdl:input name="updateAddressRequest">
  
              <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"; 
namespace="http://jaxrpcdynproxy.wsdl.test"; use="encoded"/>
  
           </wsdl:input>
  
           <wsdl:output name="updateAddressResponse">
  
              <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"; 
namespace="http://jaxrpcdynproxy.wsdl.test"; use="encoded"/>
  
           </wsdl:output>
  
        </wsdl:operation>
  
     </wsdl:binding>
  
     <wsdl:service name="AddressInOut">
  
        <wsdl:port binding="intf:AddressSoapBinding" name="AddressInOut">
  
           <wsdlsoap:address 
location="http://localhost:8080/axis/services/AddressInOut"/>
  
        </wsdl:port>
  
     </wsdl:service>
  
  </wsdl:definitions>
  
  
  
  1.1                  
xml-axis/java/test/wsdl/jaxrpcdynproxy/AddressSoapBindingImpl.java
  
  Index: AddressSoapBindingImpl.java
  ===================================================================
  package test.wsdl.jaxrpcdynproxy;
  import test.wsdl.jaxrpcdynproxy.holders.AddressBeanHolder;
  
  public class AddressSoapBindingImpl implements 
test.wsdl.jaxrpcdynproxy.AddressService {
      
      public String updateAddress(AddressBeanHolder addressBeanHolder, int 
newPostCode) throws java.rmi.RemoteException {
          addressBeanHolder.value.setPostcode(newPostCode);
          return ("Your street : " + addressBeanHolder.value.getStreet() + "\nYour 
postCode : " + newPostCode);
      }
  }
  
  
  
  1.1                  
xml-axis/java/test/wsdl/jaxrpcdynproxy/JAXRPCDynProxyTestCase.java
  
  Index: JAXRPCDynProxyTestCase.java
  ===================================================================
  package test.wsdl.jaxrpcdynproxy;
  
  import javax.xml.namespace.QName;
  import javax.xml.rpc.Service;
  import javax.xml.rpc.ServiceFactory;
  import java.net.URL;
  import test.wsdl.jaxrpcdynproxy.holders.AddressBeanHolder;
  import junit.framework.TestCase;
  import java.net.URL;
  import java.lang.reflect.Proxy;
  
  import org.apache.axis.encoding.TypeMappingRegistry;
  import org.apache.axis.encoding.TypeMapping;
  import org.apache.axis.encoding.ser.BeanSerializerFactory;
  import org.apache.axis.encoding.ser.BeanDeserializerFactory;
  import org.apache.axis.client.AxisClientProxy;
  
  public class JAXRPCDynProxyTestCase extends TestCase {
  
    /**
     * Default constructor for use as service
     */
    public JAXRPCDynProxyTestCase() {
        super("JAXRPCDynProxyTest");
    }
  
    public JAXRPCDynProxyTestCase(String name) {
        super(name);
    }
  
    public void testInOut() throws Exception {
        URL urlWsdl = new URL("http://localhost:8080/axis/services/AddressInOut?wsdl";);
        String nameSpaceUri = "http://jaxrpcdynproxy.wsdl.test";;
        String serviceName = "AddressInOut";
        String portName = "AddressInOut";
        ServiceFactory serviceFactory = ServiceFactory.newInstance();
        Service service = serviceFactory.createService(urlWsdl, new
                QName(nameSpaceUri, serviceName));
        AddressService myProxy = (AddressService) service.getPort(new
                QName(nameSpaceUri, portName), AddressService.class);
        AddressBean addressBean = new AddressBean();
        addressBean.setStreet("55, rue des Lilas");
        AddressBeanHolder addressBeanHolder = new AddressBeanHolder(addressBean);
          
        QName qName = new QName("http://jaxrpcdynproxy.wsdl.test";, "AddressBean");
        AxisClientProxy clientProxy = (AxisClientProxy) 
Proxy.getInvocationHandler(myProxy);      
        clientProxy.getCall().registerTypeMapping(AddressBean.class,
                                                  qName,
                                                  BeanSerializerFactory.class,
                                                  BeanDeserializerFactory.class,
                                                  false);
        myProxy.updateAddress(addressBeanHolder, 75005);
        addressBean = addressBeanHolder.value;
        assertEquals("New postcode is not the expected 75005", 
addressBean.getPostcode(), 75005);
    }
  
    public static void main(String[] args) throws Exception {
        JAXRPCDynProxyTestCase test = new JAXRPCDynProxyTestCase("test");
        test.testInOut();
    }
  }
  
  
  
  1.1                  xml-axis/java/test/wsdl/jaxrpcdynproxy/build.xml
  
  Index: build.xml
  ===================================================================
  <?xml version="1.0" ?>
  <!DOCTYPE project [
          <!ENTITY properties SYSTEM "file:../../../xmls/properties.xml">
          <!ENTITY paths  SYSTEM "file:../../../xmls/path_refs.xml">
          <!ENTITY taskdefs SYSTEM "file:../../../xmls/taskdefs.xml">
          <!ENTITY taskdefs_post_compile SYSTEM 
"file:../../../xmls/taskdefs_post_compile.xml">
          <!ENTITY targets SYSTEM "file:../../../xmls/targets.xml">
  ]>
  
  <!-- ===================================================================
  <description>
     Test/Sample Component file for Axis
  
  Notes:
     This is a build file for use with the Jakarta Ant build tool.
  
  Prerequisites:
  
     jakarta-ant from http://jakarta.apache.org
  
  Build Instructions:
     To compile
          ant compile
     To execute
          ant run
  
  Author:
    Matt Seibert [EMAIL PROTECTED]
  
  Copyright:
    Copyright (c) 2002-2003 Apache Software Foundation.
  </description>
  ==================================================================== -->
  
  <project default="compile">
  
          <property name="axis.home" location="../../../" />
        <property name="componentName" value="test/wsdl/jaxrpcdynproxy"/>
  
          &properties;
          &paths;
          &taskdefs;
          &taskdefs_post_compile;
        &targets;
  
  
  <target name="clean">
      <echo message="Removing ${build.dir}/classes/${componentName} and 
${build.dir}/work/${componentName}" />
      <delete dir="${build.dir}/classes/${componentName}"/>
      <delete dir="${build.dir}/work/${componentName}"/>
  </target>
  
  <target name="copy" depends="setenv"/>
  
  <target name="compile" depends="copy">
    <echo message="Compiling test.${componentName}"/>
      <wsdl2java url="${axis.home}/test/wsdl/jaxrpcdynproxy/AddressInOut.wsdl"
                 output="${build.dir}/work"
                 serverSide="yes"
                 testcase="no">
      </wsdl2java>
  
      <copy todir="${build.dir}/work/test/wsdl/jaxrpcdynproxy" overwrite="yes">
        <fileset dir="${axis.home}/test/wsdl/jaxrpcdynproxy">
          <include name="*TestCase.java"/>
          <include name="*Impl.java"/>
        </fileset>
      </copy>
  
    <javac srcdir="${build.dir}/work/test/wsdl/jaxrpcdynproxy" destdir="${build.dest}" 
debug="${debug}" fork="${javac.fork}">
      <classpath>
          <path refid="classpath"/>
      </classpath>
      <include name="**/*.java"/>
    </javac>
  </target>
  
  <target name="run">
        <antcall target="execute-Component" />
  </target>
  
  </project>
  
  
  


Reply via email to