blob: c36ee1dd89ea3fe52fa036176e0af594beafbdc3 [file] [log] [blame]
/*
* Copyright 2001-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.axis.client;
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
* constructed with a Call object, and then each time a method is invoked
* on a dynamic proxy using this invocation handler, we simply turn it into
* a SOAP request.
*
* @author Glen Daniels (gdaniels@apache.org)
* @author C?dric Chabanois (cchabanois@ifrance.com)
*/
public class AxisClientProxy implements InvocationHandler {
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, QName portName)
{
this.call = call;
this.portName = portName; // can be null
}
/**
* Map between the parameters for the method call and the parameters needed
* for the <code>Call</code>.
* <p>
* 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; proxyParams != null && 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()));
}
}
}
// fixme: what is o used for?
/**
* Handle a method invocation.
*
* @param o the object to invoke relative to
* @param method the <code>Method</code> to invoke
* @param objects the arguments to the method
* @return the result of the method
* @throws Throwable if anything went wrong in method dispatching or the
* execution of the method itself
*/
public Object invoke(Object o, Method method, Object[] objects)
throws Throwable {
// first see if we invoke Stub methods
if (method.getName().equals("_setProperty")) {
call.setProperty((String) objects[0], objects[1]);
return null;
} else if (method.getName().equals("_getProperty")) {
return call.getProperty((String) objects[0]);
} else if (method.getName().equals("_getPropertyNames")) {
return call.getPropertyNames();
} else if (Object.class.equals(method.getDeclaringClass())) {
// if we invoke basic Object methods : delegate to Call instance
return method.invoke(call, objects);
} else {
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 the current <code>Call</code>
*/
public Call getCall(){
return call;
}
}