KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > axis > client > AxisClientProxy


1 /*
2 * The Apache Software License, Version 1.1
3 *
4 *
5 * Copyright (c) 2001-2003 The Apache Software Foundation. All rights
6 * reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * 3. The end-user documentation included with the redistribution,
21 * if any, must include the following acknowledgment:
22 * "This product includes software developed by the
23 * Apache Software Foundation (http://www.apache.org/)."
24 * Alternately, this acknowledgment may appear in the software itself,
25 * if and wherever such third-party acknowledgments normally appear.
26 *
27 * 4. The names "Axis" and "Apache Software Foundation" must
28 * not be used to endorse or promote products derived from this
29 * software without prior written permission. For written
30 * permission, please contact apache@apache.org.
31 *
32 * 5. Products derived from this software may not be called "Apache",
33 * nor may "Apache" appear in their name, without prior written
34 * permission of the Apache Software Foundation.
35 *
36 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47 * SUCH DAMAGE.
48 * ====================================================================
49 *
50 * This software consists of voluntary contributions made by many
51 * individuals on behalf of the Apache Software Foundation. For more
52 * information on the Apache Software Foundation, please see
53 * <http://www.apache.org/>.
54 */

55
56 package org.jboss.axis.client;
57
58 import org.jboss.axis.AxisFault;
59 import org.jboss.axis.Constants;
60 import org.jboss.axis.description.OperationDesc;
61 import org.jboss.axis.description.ParameterDesc;
62 import org.jboss.axis.enums.Style;
63 import org.jboss.axis.enums.Use;
64 import org.jboss.axis.utils.JavaUtils;
65 import org.jboss.logging.Logger;
66
67 import javax.activation.DataHandler JavaDoc;
68 import javax.xml.namespace.QName JavaDoc;
69 import javax.xml.rpc.ServiceException JavaDoc;
70 import javax.xml.rpc.holders.Holder JavaDoc;
71 import java.lang.reflect.Constructor JavaDoc;
72 import java.lang.reflect.InvocationHandler JavaDoc;
73 import java.lang.reflect.Method JavaDoc;
74 import java.util.ArrayList JavaDoc;
75 import java.util.Map JavaDoc;
76
77 /**
78  * Very simple dynamic proxy InvocationHandler class. This class is
79  * constructed with a Call object, and then each time a method is invoked
80  * on a dynamic proxy using this invocation handler, we simply turn it into
81  * a SOAP request.
82  *
83  * @author Glen Daniels (gdaniels@macromedia.com)
84  * @author Cédric Chabanois (cchabanois@ifrance.com)
85  */

86 public class AxisClientProxy implements InvocationHandler JavaDoc
87 {
88
89    private static Logger log = Logger.getLogger(AxisClientProxy.class.getName());
90
91    private Call call;
92    private QName JavaDoc portName;
93
94    /**
95     * Constructor - package access only (should only really get used
96     * in Service.getPort(endpoint, proxyClass).
97     * Call can be pre-filled from wsdl
98     */

99    AxisClientProxy(Call call, QName JavaDoc portName)
100    {
101       this.call = call;
102       this.portName = portName; // can be null
103
}
104
105
106    /**
107     * Parameters for invoke method are not the same as parameter for Call
108     * instance :
109     * - Holders must be converted to their mapped java types
110     * - only in and inout parameters must be present in call parameters
111     *
112     * @param proxyParams proxyParameters
113     * @return Object[] Call parameters
114     * @throws JavaUtils.HolderException
115     */

116    private Object JavaDoc[] proxyParams2CallParams(Object JavaDoc[] proxyParams)
117            throws JavaUtils.HolderException, ServiceException JavaDoc
118    {
119       ArrayList JavaDoc callParams = new ArrayList JavaDoc();
120
121       OperationDesc operationDesc = call.getOperation();
122       if (operationDesc == null || proxyParams == null)
123       {
124          // we don't know which parameters are IN, OUT or INOUT
125
// let's suppose they are all in
126
return proxyParams;
127       }
128
129       // A document/literal method invocation may have more than one parameter,
130
// that must be mapped to the single IN parameter wrapper.
131
boolean isDocumentLiteral = Style.DOCUMENT.equals(operationDesc.getStyle()) && Use.LITERAL.equals(operationDesc.getUse());
132       if (isDocumentLiteral)
133       {
134          int proxyIndex = 0;
135          ArrayList JavaDoc opParams = operationDesc.getParameters();
136          for (int i = 0; i < opParams.size(); i++)
137          {
138             ParameterDesc parameterDesc = (ParameterDesc)opParams.get(i);
139             Class JavaDoc javaType = parameterDesc.getJavaType();
140
141             // The javaType is not defined or the proxy param is null
142
if (javaType == null || proxyParams[proxyIndex] == null)
143             {
144                callParams.add(proxyParams[proxyIndex++]);
145                continue;
146             }
147
148             // Check if the call param type is assignable from the proxy param
149
Class JavaDoc proxyType = proxyParams[proxyIndex].getClass();
150             if (javaType.isAssignableFrom(proxyType))
151             {
152                callParams.add(proxyParams[proxyIndex++]);
153                continue;
154             }
155
156             // Check if the call param type is convertable from the proxy param
157
if (JavaUtils.isConvertable(proxyType, javaType))
158             {
159                Object JavaDoc param = JavaUtils.convert(proxyParams[proxyIndex++], javaType);
160                callParams.add(param);
161                continue;
162             }
163
164             // Get the constructors for the call param type
165
boolean ctorFound = false;
166             Constructor JavaDoc[] ctors = javaType.getConstructors();
167             for (int j = 0; j < ctors.length; j++)
168             {
169                boolean paramsMatch = true;
170
171                // check if the proxy params match
172
Constructor JavaDoc ctor = ctors[j];
173                Class JavaDoc[] ctorTypes = ctor.getParameterTypes();
174                if (ctorTypes.length > 0)
175                {
176                   Object JavaDoc[] ctorVals = new Object JavaDoc[ctorTypes.length];
177                   for (int k = 0; paramsMatch && k < ctorTypes.length; k++)
178                   {
179                      if (ctorTypes[k].isAssignableFrom(proxyParams[proxyIndex + k].getClass()))
180                         ctorVals[k] = proxyParams[proxyIndex + k];
181                      else
182                         paramsMatch = false;
183                   }
184
185                   if (paramsMatch)
186                   {
187                      try
188                      {
189                         Object JavaDoc inst = ctor.newInstance(ctorVals);
190                         proxyIndex += ctorVals.length;
191                         callParams.add(inst);
192                         ctorFound = true;
193                         break;
194                      }
195                      catch (Exception JavaDoc e)
196                      {
197                         throw new ServiceException JavaDoc("Cannot map proxy params to: " + javaType);
198                      }
199                   }
200                }
201             }
202
203             // Let's somebody else sort it out
204
if (ctorFound == false)
205                callParams.add(proxyParams[proxyIndex++]);
206          }
207       }
208
209       // not document/literal
210
else
211       {
212          for (int i = 0; proxyParams != null && i < proxyParams.length; i++)
213          {
214             Object JavaDoc param = proxyParams[i];
215             ParameterDesc paramDesc = operationDesc.getParameter(i);
216             if (paramDesc == null)
217                throw new ServiceException JavaDoc("Cannot obtain parameter " + i + " for: " + operationDesc);
218
219             if (paramDesc.getMode() == ParameterDesc.INOUT)
220             {
221                callParams.add(JavaUtils.getHolderValue((Holder JavaDoc)param));
222             }
223             else if (paramDesc.getMode() == ParameterDesc.IN)
224             {
225                callParams.add(param);
226             }
227          }
228       }
229
230       return callParams.toArray();
231    }
232
233    /**
234     * Set the return type class on the operation desc
235     * TDI 23-June-2004
236     */

237    private void proxyReturn2CallReturn(Class JavaDoc proxyReturn)
238    {
239
240       OperationDesc operationDesc = call.getOperation();
241       if (operationDesc != null)
242       {
243          Class JavaDoc operationReturn = operationDesc.getReturnClass();
244          if (proxyReturn != null && operationReturn != null)
245          {
246             // Always use the DataHandler deserializer if the proxy return
247
// type is DataHandler
248
if (proxyReturn.equals(DataHandler JavaDoc.class))
249             {
250                operationDesc.setReturnClass(DataHandler JavaDoc.class);
251                operationDesc.setReturnType(Constants.MIME_DATA_HANDLER);
252             }
253
254             boolean isConvertible = JavaUtils.isConvertable(operationReturn, proxyReturn);
255             if (isConvertible == false)
256                isConvertible = getDocLitResultWrapper(operationReturn, proxyReturn) != null;
257
258             if (isConvertible == false)
259             {
260                log.debug("Fixing return class: " + operationReturn + " -> " + proxyReturn);
261                operationDesc.setReturnClass(proxyReturn);
262             }
263          }
264
265          if (proxyReturn == null && operationReturn != null)
266          {
267             log.debug("Forcing return class to null: " + operationReturn);
268             operationDesc.setReturnClass(null);
269          }
270       }
271    }
272
273    /** With doc/literal it is possible that the call returns a wrapper object that contains the proxy return
274     * [TDI] 05-Oct-2004
275     */

276    private Method JavaDoc getDocLitResultWrapper(Class JavaDoc callReturn, Class JavaDoc proxyReturn)
277    {
278       Method JavaDoc getter = null;
279       OperationDesc operationDesc = call.getOperation();
280
281       // With document/literal, check if operation return has a getter that returns the proxy return
282
boolean isDocumentLiteral = Style.DOCUMENT.equals(operationDesc.getStyle()) && Use.LITERAL.equals(operationDesc.getUse());
283       if (isDocumentLiteral)
284       {
285          Method JavaDoc[] methods = callReturn.getMethods();
286          for (int i = 0; getter == null && i < methods.length; i++)
287          {
288             Method JavaDoc method = methods[i];
289             if (method.getName().startsWith("get") && method.getParameterTypes().length == 0 && proxyReturn.isAssignableFrom(method.getReturnType()))
290             {
291                log.debug("Trying to unwrap proxy return with: " + method);
292                getter = method;
293             }
294          }
295       }
296
297       return getter;
298    }
299
300    /**
301     * copy in/out and out parameters (Holder parameters) back to proxyParams
302     *
303     * @param proxyParams proxyParameters
304     */

305    private void callOutputParams2proxyParams(Object JavaDoc[] proxyParams)
306            throws JavaUtils.HolderException
307    {
308       OperationDesc operationDesc = call.getOperation();
309       if (operationDesc == null || proxyParams == null)
310       {
311          // we don't know which parameters are IN, OUT or INOUT
312
// let's suppose they are all in
313
return;
314       }
315
316       Map JavaDoc outputParams = call.getOutputParams();
317
318       for (int i = 0; i < operationDesc.getNumParams(); i++)
319       {
320          Object JavaDoc param = proxyParams[i];
321          ParameterDesc paramDesc = operationDesc.getParameter(i);
322          if (paramDesc.getMode() != ParameterDesc.IN)
323          {
324             Object JavaDoc value = outputParams.get(paramDesc.getQName());
325
326             // [TDI 14-Aug-2004] The output param is already a holder
327
if (Holder JavaDoc.class.isAssignableFrom(value.getClass()))
328                value = JavaUtils.getHolderValue(value);
329
330             JavaUtils.setHolderValue((Holder JavaDoc)param, value);
331          }
332       }
333    }
334
335
336    /**
337     * Handle a method invocation.
338     */

339    public Object JavaDoc invoke(Object JavaDoc o, Method JavaDoc method, Object JavaDoc[] objects)
340            throws Throwable JavaDoc
341    {
342       try
343       {
344          if (method.getName().equals("_setProperty"))
345          {
346             call.setProperty((String JavaDoc)objects[0], objects[1]);
347             return null;
348          }
349          else if (method.getName().equals("_getProperty"))
350          {
351             return call.getProperty((String JavaDoc)objects[0]);
352
353          }
354          else if (method.getName().equals("hashCode"))
355          {
356             return new Integer JavaDoc(call.hashCode());
357
358          }
359          else if (method.getName().equals("toString"))
360          {
361             return call.toString();
362
363          }
364          else if (method.getName().equals("equals"))
365          {
366             return new Boolean JavaDoc(o == objects[0]);
367
368          }
369          else
370          {
371             Object JavaDoc outValue;
372             Object JavaDoc[] paramsCall;
373
374             if ((call.getTargetEndpointAddress() != null) && (call.getPortName() != null))
375             {
376                // call object has been prefilled : targetEndPoint and portname
377
// are already set. We complete it with method informations
378
call.setOperation(method.getName());
379                paramsCall = proxyParams2CallParams(objects);
380                proxyReturn2CallReturn(method.getReturnType());
381                outValue = call.invoke(paramsCall);
382             }
383             else if (portName != null)
384             {
385                // we only know the portName. Try to complete this information
386
// from wsdl if available
387
call.setOperation(portName, method.getName());
388                paramsCall = proxyParams2CallParams(objects);
389                proxyReturn2CallReturn(method.getReturnType());
390                outValue = call.invoke(paramsCall);
391             }
392             else
393             {
394                // we don't even know the portName (we don't have wsdl)
395
paramsCall = objects;
396                proxyReturn2CallReturn(method.getReturnType());
397                outValue = call.invoke(method.getName(), paramsCall);
398             }
399
400             callOutputParams2proxyParams(objects);
401             outValue = callReturn2ProxyReturn(outValue, method.getReturnType());
402
403             return outValue;
404          }
405       }
406       catch (AxisFault af)
407       {
408          if (af.detail != null)
409          {
410             throw af.detail;
411          }
412          throw af;
413       }
414    }
415
416    /** Convert the call return value to the actual proxy return type
417     * [TDI] 05-Oct-2004
418     */

419    private Object JavaDoc callReturn2ProxyReturn(Object JavaDoc callReturn, Class JavaDoc proxyReturnType)
420    {
421       // Nothing to do
422
if (callReturn == null)
423          return callReturn;
424
425       // try normal convertion
426
if (JavaUtils.isConvertable(callReturn, proxyReturnType))
427          return JavaUtils.convert(callReturn, proxyReturnType);
428
429       // convert an ArrayList
430
if (callReturn instanceof ArrayList JavaDoc)
431          return convertArrayList(callReturn);
432
433       Class JavaDoc callReturnType = callReturn.getClass();
434       Method JavaDoc docLitResultWrapper = getDocLitResultWrapper(callReturnType, proxyReturnType);
435       if (docLitResultWrapper != null)
436       {
437          try
438          {
439             Object JavaDoc proxyReturn = docLitResultWrapper.invoke(callReturn, new Object JavaDoc[]{});
440             return proxyReturn;
441          }
442          catch (Exception JavaDoc e)
443          {
444             log.error("Cannot unwrap call return", e);
445          }
446       }
447
448       log.warn("Cannot convert call return " + callReturnType.getName() + " to: " + proxyReturnType.getName());
449       return callReturn;
450    }
451
452    private Object JavaDoc convertArrayList(Object JavaDoc outValue)
453    {
454       Object JavaDoc value = ((ArrayList JavaDoc)outValue).toArray();
455
456       //This is a hack due to the array type of unknown types being Object[]
457
if (value.getClass().isArray())
458       {
459          if (!value.getClass().getComponentType().isPrimitive())
460          {
461             int len = java.lang.reflect.Array.getLength(value);
462             Class JavaDoc type = null;
463             for (int x = 0; x < len; x++)
464             {
465                Object JavaDoc o = java.lang.reflect.Array.get(value, x);
466                if (o != null)
467                {
468                   if (type == null)
469                   {
470                      type = o.getClass();
471                   }
472                   else
473                   {
474                      if (!type.getName().equals(o.getClass().getName()))
475                      {
476                         type = null;
477                         break;
478                      }
479                   }
480                }
481             }
482             // did we find that all elements were of same type
483
if (type != null)
484             {
485                Object JavaDoc convertedArray = java.lang.reflect.Array.newInstance(type, len);
486                System.arraycopy(value, 0, convertedArray, 0, len);
487                value = convertedArray;
488             }
489          }
490       }
491
492       return value;
493    }
494
495    /**
496     * Returns the current call
497     *
498     * @return call
499     */

500    public Call getCall()
501    {
502       return call;
503    }
504 }
505
Popular Tags