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>