Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/apache/axis/client/Call.java


1   /*
2    * Copyright 2001-2004 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.apache.axis.client ;
18  
19  import org.apache.axis.AxisFault;
20  import org.apache.axis.AxisProperties;
21  import org.apache.axis.Constants;
22  import org.apache.axis.Handler;
23  import org.apache.axis.InternalException;
24  import org.apache.axis.Message;
25  import org.apache.axis.MessageContext;
26  import org.apache.axis.AxisEngine;
27  import org.apache.axis.SOAPPart;
28  import org.apache.axis.attachments.Attachments;
29  import org.apache.axis.components.logger.LogFactory;
30  import org.apache.axis.description.FaultDesc;
31  import org.apache.axis.description.OperationDesc;
32  import org.apache.axis.description.ParameterDesc;
33  import org.apache.axis.encoding.DeserializerFactory;
34  import org.apache.axis.encoding.SerializationContext;
35  import org.apache.axis.encoding.SerializerFactory;
36  import org.apache.axis.encoding.TypeMapping;
37  import org.apache.axis.encoding.TypeMappingRegistry;
38  import org.apache.axis.encoding.XMLType;
39  import org.apache.axis.encoding.ser.BaseDeserializerFactory;
40  import org.apache.axis.encoding.ser.BaseSerializerFactory;
41  import org.apache.axis.constants.Style;
42  import org.apache.axis.constants.Use;
43  import org.apache.axis.handlers.soap.SOAPService;
44  import org.apache.axis.message.RPCElement;
45  import org.apache.axis.message.RPCHeaderParam;
46  import org.apache.axis.message.RPCParam;
47  import org.apache.axis.message.SOAPBodyElement;
48  import org.apache.axis.message.SOAPEnvelope;
49  import org.apache.axis.message.SOAPFault;
50  import org.apache.axis.message.SOAPHeaderElement;
51  import org.apache.axis.soap.SOAPConstants;
52  import org.apache.axis.transport.http.HTTPTransport;
53  import org.apache.axis.utils.ClassUtils;
54  import org.apache.axis.utils.JavaUtils;
55  import org.apache.axis.utils.Messages;
56  import org.apache.axis.utils.LockableHashtable;
57  import org.apache.axis.wsdl.symbolTable.BindingEntry;
58  import org.apache.axis.wsdl.symbolTable.Parameter;
59  import org.apache.axis.wsdl.symbolTable.Parameters;
60  import org.apache.axis.wsdl.symbolTable.SymbolTable;
61  import org.apache.axis.wsdl.symbolTable.FaultInfo;
62  import org.apache.axis.wsdl.toJava.Utils;
63  import org.apache.commons.logging.Log;
64  
65  import javax.wsdl.Binding;
66  import javax.wsdl.BindingInput;
67  import javax.wsdl.BindingOperation;
68  import javax.wsdl.Operation;
69  import javax.wsdl.extensions.mime.MIMEPart;
70  import javax.wsdl.extensions.mime.MIMEMultipartRelated;
71  import javax.wsdl.Part;
72  import javax.wsdl.Port;
73  import javax.wsdl.PortType;
74  import javax.wsdl.extensions.soap.SOAPAddress;
75  import javax.wsdl.extensions.soap.SOAPBody;
76  import javax.wsdl.extensions.soap.SOAPOperation;
77  import javax.xml.namespace.QName;
78  import javax.xml.rpc.JAXRPCException;
79  import javax.xml.rpc.ParameterMode;
80  import javax.xml.soap.SOAPException;
81  import javax.xml.soap.SOAPMessage;
82  
83  import java.io.StringWriter;
84  import java.net.MalformedURLException;
85  import java.net.URL;
86  import java.util.ArrayList;
87  import java.util.HashMap;
88  import java.util.Hashtable;
89  import java.util.Iterator;
90  import java.util.List;
91  import java.util.Map;
92  import java.util.StringTokenizer;
93  import java.util.Vector;
94  import java.rmi.RemoteException;
95  
96  /**
97   * Axis' JAXRPC Dynamic Invocation Interface implementation of the Call
98   * interface.  This class should be used to actually invoke the Web Service.
99   * It can be prefilled by a WSDL document (on the constructor to the Service
100  * object) or you can fill in the data yourself.
101  * <pre>
102  * Standard properties defined by in JAX-RPC's javax..xml.rpc.Call interface:
103  *     USERNAME_PROPERTY        - User name for authentication
104  *     PASSWORD_PROPERTY        - Password for authentication
105  *     SESSION_PROPERTY         - Participate in a session with the endpoint?
106  *     OPERATION_STYLE_PROPERTY - "rpc" or "document"
107  *     SOAPACTION_USE_PROPERTY  - Should SOAPAction be used?
108  *     SOAPACTION_URI_PROPERTY  - If SOAPAction is used, this is that action
109  *     ENCODING_STYLE_PROPERTY  - Default is SOAP 1.1:  "http://schemas.xmlsoap.org/soap/encoding/"
110  *
111  * AXIS properties:
112  *     SEND_TYPE_ATTR - Should we send the XSI type attributes (true/false)
113  *     TIMEOUT        - Timeout used by transport sender in milliseconds
114  *     TRANSPORT_NAME - Name of transport handler to use
115  *     ATTACHMENT_ENCAPSULATION_FORMAT- Send attachments as MIME the default, or DIME.
116  *     CHARACTER_SET_ENCODING - Character set encoding to use for request
117  * </pre>
118  *
119  * @author Doug Davis (dug@us.ibm.com)
120  * @author Steve Loughran
121  */
122 
123 public class Call implements javax.xml.rpc.Call {
124     protected static Log log =
125         LogFactory.getLog(Call.class.getName());
126     private static Log tlog =
127         LogFactory.getLog(Constants.TIME_LOG_CATEGORY);
128 
129     // The enterprise category is for stuff that an enterprise product might
130     // want to track, but in a simple environment (like the AXIS build) would
131     // be nothing more than a nuisance.
132     protected static Log entLog =
133         LogFactory.getLog(Constants.ENTERPRISE_LOG_CATEGORY);
134 
135     private boolean            parmAndRetReq   = true ;
136     private Service            service         = null ;
137     private QName              portName        = null;
138     private QName              portTypeName    = null;
139     private QName              operationName   = null ;
140 
141     private MessageContext     msgContext      = null ;
142 
143     // Collection of properties to store and put in MessageContext at
144     // invoke() time.  Known ones are stored in actual variables for
145     // efficiency/type-consistency.  Unknown ones are in myProperties.
146     private LockableHashtable  myProperties    = new LockableHashtable();
147     private String             username        = null;
148     private String             password        = null;
149     private boolean            maintainSession = false;
150     private boolean            useSOAPAction   = false;
151     private String             SOAPActionURI   = null;
152     private Integer            timeout         = null;
153     private boolean            useStreaming    = false;
154 
155     /** Metadata for the operation associated with this Call */
156     private OperationDesc      operation       = null;
157     /** This will be true if an OperationDesc is handed to us whole */
158     private boolean operationSetManually       = false;
159 
160     // Is this a one-way call?
161     private boolean invokeOneWay               = false;
162     private boolean isMsg                      = false;
163 
164     // Our Transport, if any
165     private Transport          transport       = null ;
166     private String             transportName   = null ;
167 
168     // A couple places to store output parameters.
169     // As a HashMap, retrievable via QName (for getOutputParams).
170     private HashMap            outParams       = null;
171     // As a list, retrievable by index (for getOutputValues).
172     private ArrayList          outParamsList   = null;
173 
174     // A place to store any client-specified headers
175     private Vector             myHeaders       = null;
176 
177     public static final String SEND_TYPE_ATTR    = AxisEngine.PROP_SEND_XSI;
178 
179     /**
180      * This is the name of a property to set the transport of the message
181      *
182      * @see #setProperty
183      */
184     public static final String TRANSPORT_NAME    = "transport_name" ;
185 
186     /**
187      * This is the character set encoding to use for the message
188      *
189      * @see #setProperty
190      */
191     public static final String CHARACTER_SET_ENCODING = SOAPMessage.CHARACTER_SET_ENCODING;
192 
193     /**
194      * This is not the name of a property that can be set with
195      * setProperty, despite its name.
196      */
197     public static final String TRANSPORT_PROPERTY= "java.protocol.handler.pkgs";
198 
199     /**
200      * this is a property set in the message context when the invocation
201      * process begins, for the benefit of handlers
202      */
203     public static final String WSDL_SERVICE      = "wsdl.service";
204 
205     /**
206      * this is a property set in the message context when the invocation
207      * process begins, for the benefit of handlers
208      */
209     public static final String WSDL_PORT_NAME    = "wsdl.portName";
210 
211     /**
212      * @deprecated use WSDL_SERVICE instead.
213      */
214     public static final String JAXRPC_SERVICE    = WSDL_SERVICE;
215 
216     /**
217      * @deprecated use WSDL_PORT_NAME instead.
218      */
219     public static final String JAXRPC_PORTTYPE_NAME = WSDL_PORT_NAME;
220 
221     /**
222      * If this property is true, the code will throw a fault if there is no
223      * response message from the server.  Otherwise, the
224      * invoke method will return a null.
225      */
226     public static final String FAULT_ON_NO_RESPONSE = "call.FaultOnNoResponse";
227 
228     /**
229      * If this property is true, code will enforce must understand check on both
230      * the request and the response paths.
231      */ 
232     public static final String CHECK_MUST_UNDERSTAND = "call.CheckMustUnderstand";
233     
234     /**
235      * Property for setting attachment format.
236      * Can be set to either DIME or MIME (default)
237      * @see #setProperty
238      * @see #ATTACHMENT_ENCAPSULATION_FORMAT_DIME
239      * @see #ATTACHMENT_ENCAPSULATION_FORMAT_MIME
240      */
241     public static final String ATTACHMENT_ENCAPSULATION_FORMAT=
242       "attachment_encapsulation_format";
243     /**
244      * Property value for setting attachment format as MIME.
245      */
246     public static final String ATTACHMENT_ENCAPSULATION_FORMAT_MIME=
247       "axis.attachment.style.mime";
248     /**
249      * Property value for setting attachment format as DIME.
250      */
251     public static final String ATTACHMENT_ENCAPSULATION_FORMAT_DIME=
252       "axis.attachment.style.dime";
253 
254     /**
255      * Timeout property: should be accompanies by an integer
256      * @see #setProperty
257      */
258     public static final String CONNECTION_TIMEOUT_PROPERTY =
259             "axis.connection.timeout";
260 
261     /**
262      * Streaming property: should be accompanied by an boolean
263      * (i.e. NO high-fidelity recording, deserialize on the fly)
264      * @see #setProperty
265      */
266     public static final String STREAMING_PROPERTY =
267             "axis.streaming";
268     
269     /**
270      * Internal property to indicate a one way call.
271      * That will disable processing of response handlers.
272      */
273     protected static final String ONE_WAY =
274         "axis.one.way";
275 
276     /**
277      * A Hashtable mapping protocols (Strings) to Transports (classes)
278      */
279     private static Hashtable transports  = new Hashtable();
280 
281     static ParameterMode [] modes = new ParameterMode [] { null,
282                                             ParameterMode.IN,
283                                             ParameterMode.OUT,
284                                             ParameterMode.INOUT };
285 
286     /** This is true when someone has called setEncodingStyle() */
287     private boolean encodingStyleExplicitlySet = false;
288     /** This is true when someone has called setOperationUse() */
289     private boolean useExplicitlySet = false;
290 
291     /**
292      * the name of a SOAP service that the call is bound to
293      */
294     private SOAPService myService = null;
295 
296     /**
297      * these are our attachments
298      */
299     protected java.util.Vector attachmentParts = new java.util.Vector();
300 
301     /** This is false when invoke() is called. */
302     private boolean isNeverInvoked  = true;     
303 
304     static {
305         initialize();
306     }
307 
308     /************************************************************************/
309     /* Start of core JAX-RPC stuff                                          */
310     /************************************************************************/
311 
312     /**
313      * Default constructor - not much else to say.
314      *
315      * @param service  the <code>Service</code> this <code>Call</code> will
316      *              work with
317      */
318     public Call(Service service) {
319         this.service = service ;
320         AxisEngine engine = service.getEngine();
321         msgContext = new MessageContext( engine );
322         myProperties.setParent(engine.getOptions());
323         maintainSession = service.getMaintainSession();
324     }
325 
326     /**
327      * Build a call from a URL string.
328      *
329      * This is handy so that you don't have to manually call Call.initialize()
330      * in order to register custom transports.  In other words, whereas doing
331      * a new URL("local:...") would fail, new Call("local:...") works because
332      * we do the initialization of our own and any configured custom protocols. 
333      *
334      * @param url the target endpoint URL
335      * @exception MalformedURLException
336      */
337     public Call(String url) throws MalformedURLException {
338         this(new Service());
339         setTargetEndpointAddress(new URL(url));
340     }
341 
342     /**
343      * Build a call from a URL.
344      *
345      * @param url the target endpoint URL
346      */
347     public Call(URL url) {
348         this(new Service());
349         setTargetEndpointAddress(url);
350     }
351 
352     ////////////////////////////
353     //
354     // Properties and the shortcuts for common ones.
355     //
356 
357     /**
358      * Allows you to set a named property to the passed in value.
359      * There are a few known properties (like username, password, etc)
360      * that are variables in Call.  The rest of the properties are
361      * stored in a Hashtable.  These common properties should be
362      * accessed via the accessors for speed/type safety, but they may
363      * still be obtained via this method.  It's up to one of the
364      * Handlers (or the Axis engine itself) to go looking for
365      * one of them.
366      *
367      * There are various well defined properties defined in the
368      * JAX-RPC specification and declared in the Call and Stub classes.
369      * It is not possible to set any other properties beginning in java. or
370      * javax. that are not in the specification.
371      * @see javax.xml.rpc.Stub
372      * @see javax.xml.rpc.Call
373      *
374      * There are other properties implemented in this class above and
375      * beyond those of the JAX-RPC spec
376      * Specifically, ATTACHMENT_ENCAPSULATION_FORMAT, CONNECTION_TIMEOUT_PROPERTY,
377      * and TRANSPORT_NAME.
378      *
379      * It is intended that all future Axis-specific properties will begin
380      * with axis. or apache. To ensure integration with future versions Axis,
381      * use different prefixes for your own properties.
382      *
383      * Axis developers: keep this in sync with propertyNames below
384      * @see #ATTACHMENT_ENCAPSULATION_FORMAT
385      * @see #TRANSPORT_NAME
386      * @see #CONNECTION_TIMEOUT_PROPERTY
387      * @param name  Name of the property
388      * @param value Value of the property
389      */
390     public void setProperty(String name, Object value) {
391         if (name == null || value == null) {
392             throw new JAXRPCException(
393                     Messages.getMessage(name == null ?
394                                          "badProp03" : "badProp04"));
395         }
396         else if (name.equals(USERNAME_PROPERTY)) {
397             verifyStringProperty(name, value);
398             setUsername((String) value);
399         }
400         else if (name.equals(PASSWORD_PROPERTY)) {
401             verifyStringProperty(name, value);
402             setPassword((String) value);
403         }
404         else if (name.equals(SESSION_MAINTAIN_PROPERTY)) {
405             verifyBooleanProperty(name, value);
406             setMaintainSession(((Boolean) value).booleanValue());
407         }
408         else if (name.equals(OPERATION_STYLE_PROPERTY)) {
409             verifyStringProperty(name, value);
410             setOperationStyle((String) value);
411             if (getOperationStyle() == Style.DOCUMENT ||
412                 getOperationStyle() == Style.WRAPPED) {
413                 setOperationUse(Use.LITERAL_STR);
414             } else if (getOperationStyle() == Style.RPC) {
415                 setOperationUse(Use.ENCODED_STR);
416             }
417         }
418         else if (name.equals(SOAPACTION_USE_PROPERTY)) {
419             verifyBooleanProperty(name, value);
420             setUseSOAPAction(((Boolean) value).booleanValue());
421         }
422         else if (name.equals(SOAPACTION_URI_PROPERTY)) {
423             verifyStringProperty(name, value);
424             setSOAPActionURI((String) value);
425         }
426         else if (name.equals(ENCODINGSTYLE_URI_PROPERTY)) {
427             verifyStringProperty(name, value);
428             setEncodingStyle((String) value);
429         }
430         else if (name.equals(Stub.ENDPOINT_ADDRESS_PROPERTY)) {
431             verifyStringProperty(name, value);
432             setTargetEndpointAddress((String) value);
433         }
434         else if ( name.equals(TRANSPORT_NAME) ) {
435             verifyStringProperty(name, value);
436             transportName = (String) value ;
437             if (transport != null) {
438                 transport.setTransportName((String) value);
439             }
440         }
441         else if ( name.equals(ATTACHMENT_ENCAPSULATION_FORMAT) ) {
442             verifyStringProperty(name, value);
443             if(!value.equals(ATTACHMENT_ENCAPSULATION_FORMAT_MIME ) &&
444                !value.equals(ATTACHMENT_ENCAPSULATION_FORMAT_DIME ))
445                 throw new JAXRPCException(
446                         Messages.getMessage("badattachmenttypeerr", new String[] {
447                         (String) value, ATTACHMENT_ENCAPSULATION_FORMAT_MIME + " "
448                         +ATTACHMENT_ENCAPSULATION_FORMAT_DIME  }));
449         }
450         else if (name.equals(CONNECTION_TIMEOUT_PROPERTY)) {
451             verifyIntegerProperty(name,value);
452             setTimeout((Integer)value);
453         }
454         else if (name.equals(STREAMING_PROPERTY)) {
455             verifyBooleanProperty(name, value);
456             setStreaming(((Boolean) value).booleanValue());
457         }
458         else if (name.equals(CHARACTER_SET_ENCODING)) {
459             verifyStringProperty(name, value);
460         }
461         else if (name.startsWith("java.") || name.startsWith("javax.")) {
462             throw new JAXRPCException(
463                     Messages.getMessage("badProp05", name));
464         }
465         myProperties.put(name, value);
466     } // setProperty
467 
468     /**
469      * Verify that the type of the object is a String, and throw
470      * an i18n-ized exception if not
471      * @param name
472      * @param value
473      * @throws JAXRPCException if value is not a String
474      */
475     private void verifyStringProperty(String name, Object value) {
476         if (!(value instanceof String)) {
477             throw new JAXRPCException(
478                     Messages.getMessage("badProp00", new String[]
479                     {name,
480                     "java.lang.String",
481                     value.getClass().getName()}));
482         }
483     }
484 
485     /**
486      * Verify that the type of the object is a Boolean, and throw
487      * an i18n-ized exception if not
488      * @param name
489      * @param value
490      * @throws JAXRPCException if value is not a Boolean
491      */
492     private void verifyBooleanProperty(String name, Object value) {
493         if (!(value instanceof Boolean)) {
494             throw new JAXRPCException(
495                     Messages.getMessage("badProp00", new String[]
496                     {name,
497                     "java.lang.Boolean",
498                     value.getClass().getName()}));
499         }
500     }
501 
502     /**
503      * Verify that the type of the object is an Integer, and throw
504      * an i18n-ized exception if not
505      * @param name
506      * @param value
507      * @throws JAXRPCException if value is not an Integer
508      */
509     private void verifyIntegerProperty(String name, Object value) {
510         if (!(value instanceof Integer)) {
511             throw new JAXRPCException(
512                     Messages.getMessage("badProp00", new String[]
513                     {name,
514                      "java.lang.Integer",
515                      value.getClass().getName()}));
516         }
517     }
518 
519     /**
520      * Returns the value associated with the named property.
521      *
522      * @param name the name of the property
523      * @return Object value of the property or null if the property is not set
524      * @throws JAXRPCException if the requested property is not a supported property
525      */
526     public Object getProperty(String name) {
527         if (name == null || !isPropertySupported(name)) {
528             throw new JAXRPCException(name == null ?
529                   Messages.getMessage("badProp03") :
530                   Messages.getMessage("badProp05", name));
531         }
532         return myProperties.get(name);
533     } // getProperty
534 
535     /**
536       * Removes (if set) the named property.
537       *
538       * @param name name of the property to remove
539       */
540      public void removeProperty(String name) {
541          if (name == null || !isPropertySupported(name)) {
542             throw new JAXRPCException(name == null ?
543                   Messages.getMessage("badProp03") :
544                   Messages.getMessage("badProp05", name));
545          }
546          myProperties.remove(name);
547      } // removeProperty
548 
549     /**
550      * Configurable properties supported by this Call object.
551      */
552     private static ArrayList propertyNames = new ArrayList();
553     static {
554         propertyNames.add(USERNAME_PROPERTY);
555         propertyNames.add(PASSWORD_PROPERTY);
556         propertyNames.add(SESSION_MAINTAIN_PROPERTY);
557         propertyNames.add(OPERATION_STYLE_PROPERTY);
558         propertyNames.add(SOAPACTION_USE_PROPERTY);
559         propertyNames.add(SOAPACTION_URI_PROPERTY);
560         propertyNames.add(ENCODINGSTYLE_URI_PROPERTY);
561         propertyNames.add(Stub.ENDPOINT_ADDRESS_PROPERTY);
562         propertyNames.add(TRANSPORT_NAME);
563         propertyNames.add(ATTACHMENT_ENCAPSULATION_FORMAT);
564         propertyNames.add(CONNECTION_TIMEOUT_PROPERTY);
565         propertyNames.add(CHARACTER_SET_ENCODING);
566     }
567 
568     public Iterator getPropertyNames() {
569         return propertyNames.iterator();
570     }
571 
572     public boolean isPropertySupported(String name) {
573         return propertyNames.contains(name) || (!name.startsWith("java.")
574                && !name.startsWith("javax."));
575     }
576 
577     /**
578      * Set the username.
579      *
580      * @param username  the new user name
581      */
582     public void setUsername(String username) {
583         this.username = username;
584     } // setUsername
585 
586     /**
587      * Get the user name.
588      *
589      * @return the user name
590      */
591     public String getUsername() {
592         return username;
593     } // getUsername
594 
595     /**
596      * Set the password.
597      *
598      * @param password  plain-text copy of the password
599      */
600     public void setPassword(String password) {
601         this.password = password;
602     } // setPassword
603 
604     /**
605      * Get the password.
606      *
607      * @return a plain-text copy of the password
608      */
609     public String getPassword() {
610         return password;
611     } // getPassword
612 
613     /**
614      * Determine whether we'd like to track sessions or not.  This
615      * overrides the default setting from the service.
616      * This just passes through the value into the MessageContext.
617      * Note: Not part of JAX-RPC specification.
618      *
619      * @param yesno true if session state is desired, false if not.
620      */
621     public void setMaintainSession(boolean yesno) {
622         maintainSession = yesno;
623     }
624 
625     /**
626      * Get the value of maintainSession flag.
627      *
628      * @return true if session is maintained, false otherwise
629      */
630     public boolean getMaintainSession() {
631         return maintainSession;
632     }
633 
634     /**
635      * Set the operation style: "document", "rpc"
636      * @param operationStyle string designating style
637      */
638     public void setOperationStyle(String operationStyle) {
639         Style style = Style.getStyle(operationStyle, Style.DEFAULT);
640         setOperationStyle(style);
641     } // setOperationStyle
642 
643     /**
644      * Set the operation style
645      *
646      * @param operationStyle
647      */
648     public void setOperationStyle(Style operationStyle) {
649         if (operation == null) {
650             operation = new OperationDesc();
651         }
652 
653         operation.setStyle(operationStyle);
654 
655         // If no one has explicitly set the use, we should track
656         // the style.  If it's non-RPC, default to LITERAL.
657         if (!useExplicitlySet) {
658             if (operationStyle != Style.RPC) {
659                 operation.setUse(Use.LITERAL);
660             }
661         }
662 
663         // If no one has explicitly set the encodingStyle, we should
664         // track the style.  If it's RPC, default to SOAP-ENC, otherwise
665         // default to "".
666         if (!encodingStyleExplicitlySet) {
667             String encStyle = "";
668             if (operationStyle == Style.RPC) {
669                 // RPC style defaults to encoded, otherwise default to literal
670                 encStyle = msgContext.getSOAPConstants().getEncodingURI();
671             }
672             msgContext.setEncodingStyle(encStyle);
673         }
674     }
675 
676     /**
677      * Get the operation style.
678      *
679      * @return the <code>Style</code> of the operation
680      */
681     public Style getOperationStyle() {
682         if (operation != null) {
683             return operation.getStyle();
684         }
685         return Style.DEFAULT;
686     } // getOperationStyle
687 
688     /**
689      * Set the operation use: "literal", "encoded"
690      * @param operationUse string designating use
691      */
692     public void setOperationUse(String operationUse) {
693         Use use = Use.getUse(operationUse, Use.DEFAULT);
694         setOperationUse(use);
695     } // setOperationUse
696 
697     /**
698      * Set the operation use
699      * @param operationUse
700      */
701     public void setOperationUse(Use operationUse) {
702         useExplicitlySet = true;
703 
704         if (operation == null) {
705             operation = new OperationDesc();
706         }
707 
708         operation.setUse(operationUse);
709         if (!encodingStyleExplicitlySet) {
710             String encStyle = "";
711             if (operationUse == Use.ENCODED) {
712                 // RPC style defaults to encoded, otherwise default to literal
713                 encStyle = msgContext.getSOAPConstants().getEncodingURI();
714             }
715             msgContext.setEncodingStyle(encStyle);
716         }
717     }
718 
719     /**
720      * Get the operation use.
721      *
722      * @return the <code>Use</code> of the operation
723      */
724     public Use getOperationUse() {
725         if (operation != null) {
726             return operation.getUse();
727         }
728         return Use.DEFAULT;
729     } // getOperationStyle
730 
731     /**
732      * Flag to indicate if soapAction should be used.
733      *
734      * @param useSOAPAction  true if the soapAction header is to be used to
735      *              help find the method to invoke, false otherwise
736      */
737     public void setUseSOAPAction(boolean useSOAPAction) {
738         this.useSOAPAction = useSOAPAction;
739     } // setUseSOAPAction
740 
741     /**
742      * Discover if soapAction is being used.
743      *
744      * @return true if it is, false otherwise
745      */
746     public boolean useSOAPAction() {
747         return useSOAPAction;
748     } // useSOAPAction
749 
750     /**
751      * Set the soapAction URI.
752      *
753      * @param SOAPActionURI  the new SOAP action URI
754      */
755     public void setSOAPActionURI(String SOAPActionURI) {
756         useSOAPAction = true;
757         this.SOAPActionURI = SOAPActionURI;
758     } // setSOAPActionURI
759 
760     /**
761      * Get the soapAction URI.
762      *
763      * @return the curretn SOAP action URI
764      */
765     public String getSOAPActionURI() {
766         return SOAPActionURI;
767     } // getSOAPActionURI
768 
769     /**
770      * Sets the encoding style to the URL passed in.
771      *
772      * @param namespaceURI URI of the encoding to use.
773      */
774     public void setEncodingStyle(String namespaceURI) {
775         encodingStyleExplicitlySet = true;
776         msgContext.setEncodingStyle(namespaceURI);
777     }
778 
779     /**
780      * Returns the encoding style as a URI that should be used for the SOAP
781      * message.
782      *
783      * @return String URI of the encoding style to use
784      */
785     public String getEncodingStyle() {
786         return msgContext.getEncodingStyle();
787     }
788 
789     /**
790      * Sets the endpoint address of the target service port. This address must
791      * correspond to the transport specified in the binding for this Call
792      * instance.
793      *
794      * @param address - Endpoint address of the target service port; specified
795      *                  as URI
796      */
797     public void setTargetEndpointAddress(String address) {
798         URL urlAddress;
799         try {
800             urlAddress = new URL(address);
801         }
802         catch (MalformedURLException mue) {
803             throw new JAXRPCException(mue);
804         }
805         setTargetEndpointAddress(urlAddress);
806     }
807 
808     /**
809      * Sets the URL of the target Web Service.
810      *
811      * Note: Not part of JAX-RPC specification.
812      *
813      * @param address URL of the target Web Service
814      */
815     public void setTargetEndpointAddress(java.net.URL address) {
816         try {
817             if ( address == null ) {
818                 setTransport(null);
819                 return ;
820             }
821 
822             String protocol = address.getProtocol();
823 
824             // Handle the case where the protocol is the same but we
825             // just want to change the URL - if so just set the URL,
826             // creating a new Transport object will drop all session
827             // data - and we want that stuff to persist between invoke()s.
828             // Technically the session data should be in the message
829             // context so that it can be persistent across transports
830             // as well, but for now the data is in the Transport object.
831             ////////////////////////////////////////////////////////////////
832             if ( this.transport != null ) {
833                 String oldAddr = this.transport.getUrl();
834                 if ( oldAddr != null && !oldAddr.equals("") ) {
835                     URL     tmpURL   = new URL( oldAddr );
836                     String  oldProto = tmpURL.getProtocol();
837                     if ( protocol.equals(oldProto) ) {
838                         this.transport.setUrl( address.toString() );
839                         return ;
840                     }
841                 }
842             }
843 
844             // Do we already have a transport for this address?
845             Transport transport = service.getTransportForURL(address);
846             if (transport != null) {
847                 setTransport(transport);
848             }
849             else {
850             // We don't already have a transport for this address.  Create one.
851                 transport = getTransportForProtocol(protocol);
852                 if (transport == null)
853                     throw new AxisFault("Call.setTargetEndpointAddress",
854                                  Messages.getMessage("noTransport01",
855                                  protocol), null, null);
856                 transport.setUrl(address.toString());
857                 setTransport(transport);
858                 service.registerTransportForURL(address, transport);
859             }
860         }
861         catch( Exception exp ) {
862             log.error(Messages.getMessage("exception00"), exp);
863             // do what?
864             // throw new AxisFault("Call.setTargetEndpointAddress",
865             //"Malformed URL Exception: " + e.getMessage(), null, null);
866         }
867     }
868 
869     /**
870      * Returns the URL of the target Web Service.
871      *
872      * @return URL URL of the target Web Service
873      */
874     public String getTargetEndpointAddress() {
875         try {
876             if ( transport == null ) return( null );
877             return( transport.getUrl() );
878         }
879         catch( Exception exp ) {
880             return( null );
881         }
882     }
883 
884     public Integer getTimeout() {
885         return timeout;
886     }
887 
888     public void setTimeout(Integer timeout) {
889         this.timeout = timeout;
890     }
891 
892     public boolean getStreaming() {
893         return useStreaming;
894     }
895 
896     public void setStreaming(boolean useStreaming) {
897         this.useStreaming = useStreaming;
898     }
899     //
900     // end properties code.
901     //
902     ////////////////////////////
903 
904     /**
905      * Is the caller required to provide the parameter and return type
906      * specification?
907      * If true, then
908      *  addParameter and setReturnType MUST be called to provide the meta data.
909      * If false, then
910      *  addParameter and setReturnType SHOULD NOT be called because the
911      *  Call object already has the meta data describing the
912      *  parameters and return type. If addParameter is called, the specified
913      *  parameter is added to the end of the list of parameters.
914      */
915     public boolean isParameterAndReturnSpecRequired(QName operationName) {
916         return parmAndRetReq;
917     } // isParameterAndReturnSpecRequired
918 
919     /**
920      * Adds the specified parameter to the list of parameters for the
921      * operation associated with this Call object.
922      *
923      * Note: Not part of JAX-RPC specification.
924      *
925      * @param paramName Name that will be used for the parameter in the XML
926      * @param xmlType XMLType of the parameter
927      * @param parameterMode one of IN, OUT or INOUT
928      */
929     public void addParameter(QName paramName, QName xmlType,
930             ParameterMode parameterMode) {
931         Class javaType = null;
932         TypeMapping tm = getTypeMapping();
933         if (tm != null) {
934             javaType = tm.getClassForQName(xmlType);
935         }
936         addParameter(paramName, xmlType, javaType, parameterMode);
937     }
938 
939     /**
940      * Adds the specified parameter to the list of parameters for the
941      * operation associated with this Call object.
942      *
943      *
944      * Note: Not part of JAX-RPC specification.
945      *
946      * @param paramName Name that will be used for the parameter in the XML
947      * @param xmlType XMLType of the parameter
948      * @param javaType The Java class of the parameter
949      * @param parameterMode one of IN, OUT or INOUT
950      */
951     public void addParameter(QName paramName, QName xmlType,
952             Class javaType, ParameterMode parameterMode) {
953 
954         if (operationSetManually) {
955             throw new RuntimeException(
956                     Messages.getMessage("operationAlreadySet"));
957         }
958 
959         if (operation == null)
960             operation = new OperationDesc();
961 
962         ParameterDesc param = new ParameterDesc();
963         byte mode = ParameterDesc.IN;
964         if (parameterMode == ParameterMode.INOUT) {
965             mode = ParameterDesc.INOUT;
966             param.setIsReturn(true);
967         } else if (parameterMode == ParameterMode.OUT) {
968             mode = ParameterDesc.OUT;
969             param.setIsReturn(true);
970         }
971         param.setMode(mode);
972         param.setQName(new QName(paramName.getNamespaceURI(),Utils.getLastLocalPart(paramName.getLocalPart())));
973         param.setTypeQName( xmlType );
974         param.setJavaType( javaType );
975 
976         operation.addParameter(param);
977         parmAndRetReq = true;
978     }
979 
980     /**
981      * Adds the specified parameter to the list of parameters for the
982      * operation associated with this Call object.
983      *
984      * @param paramName      Name that will be used for the parameter in the XML
985      * @param xmlType      XMLType of the parameter
986      * @param parameterMode  one of IN, OUT or INOUT
987      */
988     public void addParameter(String paramName, QName xmlType,
989             ParameterMode parameterMode) {
990         Class javaType = null;
991         TypeMapping tm = getTypeMapping();
992         if (tm != null) {
993             javaType = tm.getClassForQName(xmlType);
994         }
995         addParameter(new QName("", paramName), xmlType,
996                      javaType, parameterMode);
997     }
998 
999     /**
1000     * Adds a parameter type and mode for a specific operation. Note that the
1001     * client code is not required to call any addParameter and setReturnType
1002     * methods before calling the invoke method. A Call implementation class
1003     * can determine the parameter types by using the Java reflection and
1004     * configured type mapping registry.
1005     *
1006     * @param paramName - Name of the parameter
1007     * @param xmlType - XML datatype of the parameter
1008     * @param javaType - The Java class of the parameter
1009     * @param parameterMode - Mode of the parameter-whether IN, OUT or INOUT
1010     * @exception JAXRPCException - if isParameterAndReturnSpecRequired returns
1011     *                              false, then addParameter MAY throw
1012     *                              JAXRPCException....actually Axis allows
1013     *                              modification in such cases
1014     */
1015    public void addParameter(String paramName, QName xmlType,
1016                             Class javaType, ParameterMode parameterMode) {
1017        addParameter(new QName("", paramName), xmlType,
1018                     javaType, parameterMode);
1019    }
1020
1021    /**
1022     * Adds a parameter type as a soap:header.
1023     *
1024     * @param paramName     - Name of the parameter
1025     * @param xmlType       - XML datatype of the parameter
1026     * @param parameterMode - Mode of the parameter-whether IN, OUT or INOUT
1027     * @param headerMode    - Mode of the header. Even if this is an INOUT
1028     *                      parameter, it need not be in the header in both
1029     *                      directions.
1030     * @throws JAXRPCException - if isParameterAndReturnSpecRequired returns
1031     *                         false, then addParameter MAY throw
1032     *                         JAXRPCException....actually Axis allows
1033     *                         modification in such cases
1034     */
1035    public void addParameterAsHeader(QName paramName, QName xmlType,
1036                                     ParameterMode parameterMode,
1037                                     ParameterMode headerMode) {
1038        Class javaType = null;
1039        TypeMapping tm = getTypeMapping();
1040        if (tm != null) {
1041            javaType = tm.getClassForQName(xmlType);
1042        }
1043        addParameterAsHeader(paramName, xmlType, javaType,
1044                parameterMode, headerMode);
1045    }
1046     
1047    /**
1048
1049     * Adds a parameter type as a soap:header.
1050     * @param paramName - Name of the parameter
1051     * @param xmlType - XML datatype of the parameter
1052     * @param javaType - The Java class of the parameter
1053     * @param parameterMode - Mode of the parameter-whether IN, OUT or INOUT
1054     * @param headerMode - Mode of the header.  Even if this is an INOUT
1055     *                     parameter, it need not be in the header in both
1056     *                     directions.
1057     * @exception JAXRPCException - if isParameterAndReturnSpecRequired returns
1058     *                              false, then addParameter MAY throw
1059     *                              JAXRPCException....actually Axis allows
1060     *                              modification in such cases
1061     */
1062    public void addParameterAsHeader(QName paramName, QName xmlType,
1063            Class javaType, ParameterMode parameterMode,
1064            ParameterMode headerMode) {
1065        if (operationSetManually) {
1066            throw new RuntimeException(
1067                    Messages.getMessage("operationAlreadySet"));
1068        }
1069
1070        if (operation == null)
1071            operation = new OperationDesc();
1072
1073        ParameterDesc param = new ParameterDesc();
1074        param.setQName(new QName(paramName.getNamespaceURI(),Utils.getLastLocalPart(paramName.getLocalPart())));
1075        param.setTypeQName(xmlType);
1076        param.setJavaType(javaType);
1077        if (parameterMode == ParameterMode.IN) {
1078            param.setMode(ParameterDesc.IN);
1079        }
1080        else if (parameterMode == ParameterMode.INOUT) {
1081            param.setMode(ParameterDesc.INOUT);
1082        }
1083        else if (parameterMode == ParameterMode.OUT) {
1084            param.setMode(ParameterDesc.OUT);
1085        }
1086        if (headerMode == ParameterMode.IN) {
1087            param.setInHeader(true);
1088        }
1089        else if (headerMode == ParameterMode.INOUT) {
1090            param.setInHeader(true);
1091            param.setOutHeader(true);
1092        }
1093        else if (headerMode == ParameterMode.OUT) {
1094            param.setOutHeader(true);
1095        }
1096        operation.addParameter(param);
1097        parmAndRetReq = true;
1098    } // addParameterAsHeader
1099
1100    /**
1101     * Return the QName of the type of the parameters with the given name.
1102     *
1103     * @param  paramName  name of the parameter to return
1104     * @return XMLType    XMLType of paramName, or null if not found.
1105     */
1106    public QName getParameterTypeByName(String paramName) {
1107        QName paramQName = new QName("", paramName);
1108
1109        return getParameterTypeByQName(paramQName);
1110    }
1111
1112    /**
1113     * Return the QName of the type of the parameters with the given name.
1114     *
1115     * Note: Not part of JAX-RPC specification.
1116     *
1117     * @param  paramQName  QName of the parameter to return
1118     * @return XMLType    XMLType of paramQName, or null if not found.
1119     */
1120    public QName getParameterTypeByQName(QName paramQName) {
1121        ParameterDesc param = operation.getParamByQName(paramQName);
1122        if (param != null) {
1123            return param.getTypeQName();
1124        }
1125        return( null );
1126    }
1127
1128    /**
1129     * Sets the return type of the operation associated with this Call object.
1130     *
1131     * @param type QName of the return value type.
1132     */
1133    public void setReturnType(QName type) {
1134        if (operationSetManually) {
1135            throw new RuntimeException(
1136                    Messages.getMessage("operationAlreadySet"));
1137        }
1138
1139        if (operation == null)
1140            operation = new OperationDesc();
1141
1142        // In order to allow any Call to be re-used, Axis
1143        // chooses to allow setReturnType to be changed when
1144        // parmAndRetReq==false.  This does not conflict with
1145        // JSR 101 which indicates an exception MAY be thrown.
1146
1147        //if (parmAndRetReq) {
1148        operation.setReturnType(type);
1149        TypeMapping tm = getTypeMapping();
1150        operation.setReturnClass(tm.getClassForQName(type));
1151        parmAndRetReq = true;
1152        //}
1153        //else {
1154        //throw new JAXRPCException(Messages.getMessage("noParmAndRetReq"));
1155        //}
1156    }
1157
1158    /**
1159     * Sets the return type for a specific operation.
1160     *
1161     * @param xmlType - QName of the data type of the return value
1162     * @param javaType - Java class of the return value
1163     * @exception JAXRPCException - if isParameterAndReturnSpecRequired returns
1164     * false, then setReturnType MAY throw JAXRPCException...Axis allows
1165     * modification without throwing the exception.
1166     */
1167    public void setReturnType(QName xmlType, Class javaType) {
1168        setReturnType(xmlType);
1169        // Use specified type as the operation return
1170        operation.setReturnClass(javaType);
1171    }
1172
1173    /**
1174     * Set the return type as a header
1175     */
1176    public void setReturnTypeAsHeader(QName xmlType) {
1177        setReturnType(xmlType);
1178        operation.setReturnHeader(true);
1179    } // setReturnTypeAsHeader
1180
1181    /**
1182     * Set the return type as a header
1183     */
1184    public void setReturnTypeAsHeader(QName xmlType, Class javaType) {
1185        setReturnType(xmlType, javaType);
1186        operation.setReturnHeader(true);
1187    } // setReturnTypeAsHeader
1188
1189    /**
1190     * Returns the QName of the type of the return value of this Call - or null
1191     * if not set.
1192     *
1193     * Note: Not part of JAX-RPC specification.
1194     *
1195     * @return the XMLType specified for this Call (or null).
1196     */
1197    public QName getReturnType() {
1198        if (operation != null)
1199            return operation.getReturnType();
1200
1201        return null;
1202    }
1203
1204    /**
1205     * Set the QName of the return element
1206     *
1207     * NOT part of JAX-RPC
1208     */
1209    public void setReturnQName(QName qname) {
1210        if (operationSetManually) {
1211            throw new RuntimeException(
1212                    Messages.getMessage("operationAlreadySet"));
1213        }
1214
1215        if (operation == null)
1216            operation = new OperationDesc();
1217
1218        operation.setReturnQName(qname);
1219    }
1220    /**
1221     * Sets the desired return Java Class.  This is a convenience method
1222     * which will cause the Call to automatically convert return values
1223     * into a desired class if possible.  For instance, we return object
1224     * arrays by default now for SOAP arrays - you could specify:
1225     *
1226     * setReturnClass(Vector.class)
1227     *
1228     * and you'd get a Vector back from invoke() instead of having to do
1229     * the conversion yourself.
1230     *
1231     * Note: Not part of JAX-RPC specification.  To be JAX-RPC compliant,
1232     *       use setReturnType(QName, Class).
1233     *
1234     * @param cls the desired return class.
1235     */
1236    public void setReturnClass(Class cls) {
1237        if (operationSetManually) {
1238            throw new RuntimeException(
1239                    Messages.getMessage("operationAlreadySet"));
1240        }
1241
1242        if (operation == null)
1243            operation = new OperationDesc();
1244
1245        operation.setReturnClass(cls);
1246        TypeMapping tm = getTypeMapping();
1247        operation.setReturnType(tm.getTypeQName(cls));
1248        parmAndRetReq = true;
1249    }
1250
1251    /**
1252     * Clears the list of parameters.
1253     * @exception JAXRPCException - if isParameterAndReturnSpecRequired returns
1254     *  false, then removeAllParameters MAY throw JAXRPCException...Axis allows
1255     *  modification to the Call object without throwing an exception.
1256     */
1257    public void removeAllParameters() {
1258        //if (parmAndRetReq) {
1259        operation = new OperationDesc();
1260        operationSetManually = false;
1261        parmAndRetReq = true;
1262        //}
1263        //else {
1264        //throw new JAXRPCException(Messages.getMessage("noParmAndRetReq"));
1265        //}
1266    }
1267
1268    /**
1269     * Returns the operation name associated with this Call object.
1270     *
1271     * @return String Name of the operation or null if not set.
1272     */
1273    public QName getOperationName() {
1274        return( operationName );
1275    }
1276
1277    /**
1278     * Sets the operation name associated with this Call object.  This will
1279     * not check the WSDL (if there is WSDL) to make sure that it's a valid
1280     * operation name.
1281     *
1282     * @param opName Name of the operation.
1283     */
1284    public void setOperationName(QName opName) {
1285        operationName = opName ;
1286    }
1287
1288    /**
1289     * This is a convenience method.  If the user doesn't care about the QName
1290     * of the operation, the user can call this method, which converts a String
1291     * operation name to a QName.
1292     */
1293    public void setOperationName(String opName) {
1294        operationName = new QName(opName);
1295    }
1296
1297    /**
1298     * Prefill as much info from the WSDL as it can.
1299     * Right now it's SOAPAction, operation qname, parameter types
1300     * and return type of the Web Service.
1301     *
1302     * This methods considers that port name and target endpoint address have
1303     * already been set. This is useful when you want to use the same Call
1304     * instance for several calls on the same Port
1305     *
1306     * Note: Not part of JAX-RPC specification.
1307     *
1308     * @param  opName          Operation(method) that's going to be invoked
1309     * @throws JAXRPCException
1310     */
1311    public void setOperation(String opName) {
1312        if ( service == null ) {
1313            throw new JAXRPCException( Messages.getMessage("noService04") );
1314        }
1315
1316        // remove all settings concerning an operation
1317        // leave portName and targetEndPoint as they are
1318        this.setOperationName( opName );
1319        this.setEncodingStyle( null );
1320        this.setReturnType( null );
1321        this.removeAllParameters();
1322
1323        javax.wsdl.Service wsdlService = service.getWSDLService();
1324        // Nothing to do is the WSDL is not already set.
1325        if(wsdlService == null) {
1326            return;
1327        }
1328
1329        Port port = wsdlService.getPort( portName.getLocalPart() );
1330        if ( port == null ) {
1331            throw new JAXRPCException( Messages.getMessage("noPort00", "" +
1332                                                           portName) );
1333        }
1334
1335        Binding   binding  = port.getBinding();
1336        PortType  portType = binding.getPortType();
1337        if ( portType == null ) {
1338            throw new JAXRPCException( Messages.getMessage("noPortType00", "" +
1339                                                           portName) );
1340        }
1341        this.setPortTypeName(portType.getQName());
1342        
1343        List operations = portType.getOperations();
1344        if ( operations == null ) {
1345            throw new JAXRPCException( Messages.getMessage("noOperation01",
1346                                                           opName) );
1347        }
1348
1349        Operation op = null ;
1350        for ( int i = 0 ; i < operations.size() ; i++, op=null ) {
1351            op = (Operation) operations.get( i );
1352            if ( opName.equals( op.getName() ) ) {
1353                break ;
1354            }
1355        }
1356        if ( op == null ) {
1357            throw new JAXRPCException( Messages.getMessage("noOperation01",
1358                                                           opName) );
1359        }
1360
1361        // Get the SOAPAction
1362        ////////////////////////////////////////////////////////////////////
1363        List list = port.getExtensibilityElements();
1364        String opStyle = null;
1365        BindingOperation bop = binding.getBindingOperation(opName,
1366                                                           null, null);
1367        if ( bop == null ) {
1368            throw new JAXRPCException( Messages.getMessage("noOperation02",
1369                                                            opName ));
1370        }
1371        list = bop.getExtensibilityElements();
1372        for ( int i = 0 ; list != null && i < list.size() ; i++ ) {
1373            Object obj = list.get(i);
1374            if ( obj instanceof SOAPOperation ) {
1375                SOAPOperation sop    = (SOAPOperation) obj ;
1376                opStyle = ((SOAPOperation) obj).getStyle();
1377                String action = sop.getSoapActionURI();
1378                if ( action != null ) {
1379                    setUseSOAPAction(true);
1380                    setSOAPActionURI(action);
1381                }
1382                else {
1383                    setUseSOAPAction(false);
1384                    setSOAPActionURI(null);
1385                }
1386                break ;
1387            }
1388        }
1389
1390        // Get the body's namespace URI and encoding style
1391        ////////////////////////////////////////////////////////////////////
1392        BindingInput bIn = bop.getBindingInput();
1393        if ( bIn != null ) {
1394            list = bIn.getExtensibilityElements();
1395            for ( int i = 0 ; list != null && i < list.size() ; i++ ) {
1396                Object obj = list.get(i);
1397                if( obj instanceof MIMEMultipartRelated){
1398                  MIMEMultipartRelated mpr=(MIMEMultipartRelated) obj;
1399                  Object part= null;
1400                  List l=  mpr.getMIMEParts();
1401                  for(int j=0; l!= null && j< l.size() && part== null; j++){
1402                     MIMEPart mp = (MIMEPart)l.get(j);
1403                     List ll= mp.getExtensibilityElements();
1404                     for(int k=0; ll != null && k < ll.size() && part == null;
1405                           k++){
1406                       part= ll.get(k);
1407                       if ( !(part instanceof SOAPBody)) {
1408                           part = null;
1409                       }
1410                     }
1411                  }
1412                  if(null != part) {
1413                      obj= part;
1414                  }
1415                }
1416
1417                if ( obj instanceof SOAPBody ) {
1418                    SOAPBody sBody  = (SOAPBody) obj ;
1419                    list = sBody.getEncodingStyles();
1420                    if ( list != null && list.size() > 0 ) {
1421                        this.setEncodingStyle( (String) list.get(0) );
1422                    }
1423                    String ns = sBody.getNamespaceURI();
1424                    if (ns != null && !ns.equals("")) {
1425                      setOperationName( new QName( ns, opName ) );
1426                    }
1427                    break ;
1428                }
1429            }
1430        }
1431
1432        Service service = this.getService();
1433        SymbolTable symbolTable = service.getWSDLParser().getSymbolTable();
1434        BindingEntry bEntry = symbolTable.getBindingEntry(binding.getQName());
1435        Parameters parameters = bEntry.getParameters(bop.getOperation());
1436
1437        // loop over paramters and set up in/out params
1438        for (int j = 0; j < parameters.list.size(); ++j) {
1439            Parameter p = (Parameter) parameters.list.get(j);
1440            // Get the QName representing the parameter type
1441            QName paramType = Utils.getXSIType(p);
1442
1443            // checks whether p is an IN or OUT header 
1444            // and adds it as a header parameter else
1445            // add it to the body
1446            ParameterMode mode = modes[p.getMode()];
1447            if (p.isInHeader() || p.isOutHeader()) {
1448                this.addParameterAsHeader(p.getQName(), paramType,
1449                        mode, mode);
1450            } else {
1451                this.addParameter(p.getQName(), paramType, mode);
1452            } 
1453        }
1454
1455        Map faultMap = bEntry.getFaults();
1456        // Get the list of faults for this operation
1457        ArrayList faults = (ArrayList) faultMap.get(bop);
1458
1459        // check for no faults
1460        if (faults == null) {
1461            return;
1462        }
1463        // For each fault, register its information
1464        for (Iterator faultIt = faults.iterator(); faultIt.hasNext();) {
1465            FaultInfo info = (FaultInfo) faultIt.next();
1466            QName qname = info.getQName();
1467            info.getMessage();
1468
1469            // if no parts in fault, skip it!
1470            if (qname == null) {
1471                continue;
1472            }
1473
1474            QName xmlType = info.getXMLType();
1475            Class clazz = getTypeMapping().getClassForQName(xmlType);
1476            if (clazz != null) {
1477                addFault(qname, clazz, xmlType, true);
1478            } else {
1479                //we cannot map from the info to a java class
1480                //In Axis1.1 and before this was silently swallowed. Now we log it
1481
1482                log.debug(Messages.getMessage("clientNoTypemapping", xmlType.toString()));
1483            }
1484        }
1485
1486        // set output type
1487        if (parameters.returnParam != null) {
1488            // Get the QName for the return Type
1489            QName returnType = Utils.getXSIType(parameters.returnParam);
1490            QName returnQName = parameters.returnParam.getQName();
1491
1492            // Get the javaType
1493            String javaType = null;
1494            if (parameters.returnParam.getMIMEInfo() != null) {
1495                javaType = "javax.activation.DataHandler";
1496            }
1497            else {
1498                javaType = parameters.returnParam.getType().getName();
1499            }
1500            if (javaType == null) {
1501                javaType = "";
1502            }
1503            else {
1504                javaType = javaType + ".class";
1505            }
1506            this.setReturnType(returnType);
1507            try {
1508                Class clazz = ClassUtils.forName(javaType);
1509                this.setReturnClass(clazz);
1510            } catch (ClassNotFoundException swallowedException) {
1511                //log that this lookup failed,
1512                log.debug(Messages.getMessage("clientNoReturnClass",
1513                        javaType));
1514            }
1515            this.setReturnQName(returnQName);
1516        }
1517        else {
1518            this.setReturnType(org.apache.axis.encoding.XMLType.AXIS_VOID);
1519        }
1520
1521        boolean hasMIME = Utils.hasMIME(bEntry, bop);
1522        Use use = bEntry.getInputBodyType(bop.getOperation());
1523        setOperationUse(use);
1524        if (use == Use.LITERAL) {
1525            // Turn off encoding
1526            setEncodingStyle(null);
1527            // turn off XSI types
1528            setProperty(org.apache.axis.client.Call.SEND_TYPE_ATTR, Boolean.FALSE);
1529        }
1530        if (hasMIME || use == Use.LITERAL) {
1531            // If it is literal, turn off multirefs.
1532            //
1533            // If there are any MIME types, turn off multirefs.
1534            // I don't know enough about the guts to know why
1535            // attachments don't work with multirefs, but they don't.
1536            setProperty(org.apache.axis.AxisEngine.PROP_DOMULTIREFS, Boolean.FALSE);
1537        }
1538
1539        Style style = Style.getStyle(opStyle, bEntry.getBindingStyle());
1540        if (style == Style.DOCUMENT && symbolTable.isWrapped()) {
1541            style = Style.WRAPPED;
1542        }
1543        setOperationStyle(style);
1544
1545        // Operation name
1546        if (style == Style.WRAPPED) {
1547            // We need to make sure the operation name, which is what we
1548            // wrap the elements in, matches the Qname of the parameter
1549            // element.
1550            Map partsMap = bop.getOperation().getInput().getMessage().getParts();
1551            Part p = (Part)partsMap.values().iterator().next();
1552            QName q = p.getElementName();
1553            setOperationName(q);
1554        } else {
1555            QName elementQName =
1556                Utils.getOperationQName(bop, bEntry, symbolTable);
1557            if (elementQName != null) {
1558                setOperationName(elementQName);
1559            }
1560        }
1561
1562        // Indicate that the parameters and return no longer
1563        // need to be specified with addParameter calls.
1564        parmAndRetReq = false;
1565        return;
1566
1567    }
1568
1569
1570    /**
1571     * prefill as much info from the WSDL as it can.
1572     * Right now it's target URL, SOAPAction, Parameter types,
1573     * and return type of the Web Service.
1574     *
1575     * If wsdl is not present, this function set port name and operation name
1576     * and does not modify target endpoint address.
1577     *
1578     * Note: Not part of JAX-RPC specification.
1579     *
1580     * @param  portName        PortName in the WSDL doc to search for
1581     * @param  opName          Operation(method) that's going to be invoked
1582     */
1583    public void setOperation(QName portName, String opName) {
1584      setOperation(portName, new QName(opName));
1585    }
1586
1587    
1588    /**
1589     * prefill as much info from the WSDL as it can.
1590     * Right now it's target URL, SOAPAction, Parameter types,
1591     * and return type of the Web Service.
1592     *
1593     * If wsdl is not present, this function set port name and operation name
1594     * and does not modify target endpoint address.
1595     *
1596     * Note: Not part of JAX-RPC specification.
1597     *
1598     * @param  portName        PortName in the WSDL doc to search for
1599     * @param  opName          Operation(method) that's going to be invoked
1600     */
1601    public void setOperation(QName portName, QName opName) {
1602        if ( service == null )
1603            throw new JAXRPCException( Messages.getMessage("noService04") );
1604
1605        // Make sure we're making a fresh start.
1606        this.setPortName( portName );
1607        this.setOperationName( opName );
1608        this.setReturnType( null );
1609        this.removeAllParameters();
1610
1611        javax.wsdl.Service wsdlService = service.getWSDLService();
1612        // Nothing to do is the WSDL is not already set.
1613        if(wsdlService == null) {
1614            return;
1615        }
1616
1617        // we reinitialize target endpoint only if we have wsdl
1618        this.setTargetEndpointAddress( (URL) null );
1619
1620        Port port = wsdlService.getPort( portName.getLocalPart() );
1621        if ( port == null ) {
1622            throw new JAXRPCException( Messages.getMessage("noPort00", "" +
1623                                                           portName) );
1624        }
1625
1626        // Get the URL
1627        ////////////////////////////////////////////////////////////////////
1628        List list = port.getExtensibilityElements();
1629        for ( int i = 0 ; list != null && i < list.size() ; i++ ) {
1630            Object obj = list.get(i);
1631            if ( obj instanceof SOAPAddress ) {
1632                try {
1633                    SOAPAddress addr = (SOAPAddress) obj ;
1634                    URL         url  = new URL(addr.getLocationURI());
1635                    this.setTargetEndpointAddress(url);
1636                }
1637                catch(Exception exp) {
1638                    throw new JAXRPCException(
1639                            Messages.getMessage("cantSetURI00", "" + exp) );
1640                }
1641            }
1642        }
1643
1644        setOperation(opName.getLocalPart());
1645    }
1646
1647    /**
1648     * Returns the fully qualified name of the port for this Call object
1649     * (if there is one).
1650     *
1651     * @return QName Fully qualified name of the port (or null if not set)
1652     */
1653    public QName getPortName() {
1654        return( portName );
1655    } // getPortName
1656
1657    /**
1658     * Sets the port name of this Call object.  This call will not set
1659     * any additional fields, nor will it do any checking to verify that
1660     * this port name is actually defined in the WSDL - for now anyway.
1661     *
1662     * @param portName Fully qualified name of the port
1663     */
1664    public void setPortName(QName portName) {
1665        this.portName = portName;
1666    } // setPortName
1667
1668    /**
1669     * Returns the fully qualified name of the port type for this Call object
1670     * (if there is one).
1671     *
1672     * @return QName Fully qualified name of the port type
1673     */
1674    public QName getPortTypeName() {
1675        return portTypeName == null ? new QName("") : portTypeName;
1676    }
1677
1678    /**
1679     * Sets the port type name of this Call object.  This call will not set
1680     * any additional fields, nor will it do any checking to verify that
1681     * this port type is actually defined in the WSDL - for now anyway.
1682     *
1683     * @param portType Fully qualified name of the portType
1684     */
1685    public void setPortTypeName(QName portType) {
1686        this.portTypeName = portType;
1687    }
1688
1689    /**
1690     * Allow the user to set the default SOAP version.  For SOAP 1.2, pass
1691     * SOAPConstants.SOAP12_CONSTANTS.
1692     *
1693     * @param soapConstants the SOAPConstants object representing the correct
1694     *                      version
1695     */
1696    public void setSOAPVersion(SOAPConstants soapConstants) {
1697        msgContext.setSOAPConstants(soapConstants);
1698    }
1699
1700    /**
1701     * Invokes a specific operation using a synchronous request-response interaction mode. The invoke method takes
1702     * as parameters the object values corresponding to these defined parameter types. Implementation of the invoke
1703     * method must check whether the passed parameter values correspond to the number, order and types of parameters
1704     * specified in the corresponding operation specification.
1705     *
1706     * @param operationName - Name of the operation to invoke
1707     * @param params  - Parameters for this invocation
1708     *
1709     * @return the value returned from the other end.
1710     *
1711     * @throws java.rmi.RemoteException - if there is any error in the remote method invocation or if the Call
1712     * object is not configured properly.
1713     */
1714    public Object invoke(QName operationName, Object[] params)
1715      throws java.rmi.RemoteException {
1716        QName origOpName = this.operationName;
1717        this.operationName = operationName;
1718        try {
1719            return this.invoke(params);
1720        }
1721        catch (AxisFault af) {
1722            this.operationName = origOpName;
1723            if(af.detail != null && af.detail instanceof RemoteException) {
1724                throw ((RemoteException)af.detail);
1725            }
1726            throw af;
1727        }
1728        catch (java.rmi.RemoteException re) {
1729            this.operationName = origOpName;
1730            throw re;
1731        }
1732        catch (RuntimeException re) {
1733            this.operationName = origOpName;
1734            throw re;
1735        }
1736        catch (Error e) {
1737            this.operationName = origOpName;
1738            throw e;
1739        }
1740    } // invoke
1741
1742    /**
1743     * Invokes the operation associated with this Call object using the
1744     * passed in parameters as the arguments to the method.
1745     *
1746     * For Messaging (ie. non-RPC) the params argument should be an array
1747     * of SOAPBodyElements.  <b>All</b> of them need to be SOAPBodyElements,
1748     * if any of them are not this method will default back to RPC.  In the
1749     * Messaging case the return value will be a vector of SOAPBodyElements.
1750     *
1751     * @param  params Array of parameters to invoke the Web Service with
1752     * @return Object Return value of the operation/method - or null
1753     * @throws java.rmi.RemoteException if there's an error
1754     */
1755    public Object invoke(Object[] params) throws java.rmi.RemoteException {
1756        long t0=0, t1=0;
1757        if( tlog.isDebugEnabled() ) {
1758            t0=System.currentTimeMillis();
1759        }
1760        /* First see if we're dealing with Messaging instead of RPC.        */
1761        /* If ALL of the params are SOAPBodyElements then we're doing       */
1762        /* Messaging, otherwise just fall through to normal RPC processing. */
1763        /********************************************************************/
1764        SOAPEnvelope  env = null ;
1765        int i ;
1766
1767        for ( i = 0 ; params != null && i < params.length ; i++ )
1768            if ( !(params[i] instanceof SOAPBodyElement) ) break ;
1769
1770        if ( params != null && params.length > 0 && i == params.length ) {
1771            /* ok, we're doing Messaging, so build up the message */
1772            /******************************************************/
1773            isMsg = true ;
1774            env = new SOAPEnvelope(msgContext.getSOAPConstants(),
1775                                   msgContext.getSchemaVersion());
1776
1777            for (i = 0; i < params.length; i++) {
1778                env.addBodyElement((SOAPBodyElement) params[i]);
1779            }
1780
1781            Message msg = new Message( env );
1782            setRequestMessage(msg);
1783
1784            invoke();
1785
1786            msg = msgContext.getResponseMessage();
1787            if (msg == null) {
1788              if (msgContext.isPropertyTrue(FAULT_ON_NO_RESPONSE, false)) {
1789                throw new AxisFault(Messages.getMessage("nullResponse00"));
1790              } else {
1791                return null;
1792              }
1793            }
1794
1795            env = msg.getSOAPEnvelope();
1796            return( env.getBodyElements() );
1797        }
1798
1799
1800        if ( operationName == null ) {
1801            throw new AxisFault( Messages.getMessage("noOperation00") );
1802        }
1803        try {
1804            Object res=this.invoke(operationName.getNamespaceURI(),
1805                    operationName.getLocalPart(), params);
1806            if( tlog.isDebugEnabled() ) {
1807                t1=System.currentTimeMillis();
1808                tlog.debug("axis.Call.invoke: " + (t1-t0)  + " " + operationName);
1809            }
1810            return res;
1811        }
1812        catch( AxisFault af) {
1813            if(af.detail != null && af.detail instanceof RemoteException) {
1814                throw ((RemoteException)af.detail);
1815            }
1816            throw af;
1817        }
1818        catch( Exception exp ) {
1819            entLog.debug(Messages.getMessage("toAxisFault00"), exp);
1820            throw AxisFault.makeFault(exp);
1821        }
1822    }
1823
1824    /**
1825     * Invokes the operation associated with this Call object using the passed
1826     * in parameters as the arguments to the method.  This will return
1827     * immediately rather than waiting for the server to complete its
1828     * processing.
1829     *
1830     * NOTE: the return immediately part isn't implemented yet
1831     *
1832     * @param  params Array of parameters to invoke the Web Service with
1833     * @throws JAXRPCException is there's an error
1834     */
1835    public void invokeOneWay(Object[] params) {
1836        try {
1837            invokeOneWay = true;
1838            invoke( params );
1839        } catch( Exception exp ) {
1840            throw new JAXRPCException( exp.toString() );
1841        } finally {
1842            invokeOneWay = false;
1843        }
1844    }
1845
1846    /************************************************************************/
1847    /* End of core JAX-RPC stuff                                            */
1848    /************************************************************************/
1849
1850    /**
1851     * Invoke the service with a custom Message.
1852     * This method simplifies invoke(SOAPEnvelope).
1853     * <p>
1854     * Note: Not part of JAX-RPC specification.
1855     *
1856     * @param msg a Message to send
1857     * @throws AxisFault if there is any failure
1858     */
1859    public SOAPEnvelope invoke(Message msg) throws AxisFault {
1860        try {
1861            setRequestMessage( msg );
1862            invoke();
1863            msg = msgContext.getResponseMessage();
1864            if (msg == null) {
1865                if (msgContext.isPropertyTrue(FAULT_ON_NO_RESPONSE, false)) {
1866                    throw new AxisFault(Messages.getMessage("nullResponse00"));
1867                } else {
1868                    return null;
1869                }
1870            }
1871            SOAPEnvelope res = null;
1872            res = msg.getSOAPEnvelope();
1873            return res;
1874        }
1875        catch (Exception exp) {
1876            if (exp instanceof AxisFault) {
1877                throw (AxisFault) exp ;
1878            }
1879            entLog.debug(Messages.getMessage("toAxisFault00"), exp);
1880            throw new AxisFault(
1881                    Messages.getMessage("errorInvoking00", "\n" + exp));
1882        }
1883    }
1884
1885    /**
1886     * Invoke the service with a custom SOAPEnvelope.
1887     * <p>
1888     * Note: Not part of JAX-RPC specification.
1889     *
1890     * @param env a SOAPEnvelope to send
1891     * @throws AxisFault if there is any failure
1892     */
1893    public SOAPEnvelope invoke(SOAPEnvelope env) throws AxisFault {
1894        try {
1895            Message msg = new Message( env );
1896            if (getProperty(CHARACTER_SET_ENCODING) != null) {
1897                msg.setProperty(SOAPMessage.CHARACTER_SET_ENCODING, getProperty(CHARACTER_SET_ENCODING));
1898            } else if (msgContext.getProperty(CHARACTER_SET_ENCODING) != null) {
1899                msg.setProperty(CHARACTER_SET_ENCODING, msgContext.getProperty(CHARACTER_SET_ENCODING));
1900            }
1901            setRequestMessage( msg );
1902            invoke();
1903            msg = msgContext.getResponseMessage();
1904            if (msg == null) {
1905              if (msgContext.isPropertyTrue(FAULT_ON_NO_RESPONSE, false)) {
1906                throw new AxisFault(Messages.getMessage("nullResponse00"));
1907              } else {
1908                return null;
1909              }
1910            }
1911            return( msg.getSOAPEnvelope() );
1912        }
1913        catch( Exception exp ) {
1914            if ( exp instanceof AxisFault ) {
1915                throw (AxisFault) exp ;
1916            }
1917
1918            entLog.debug(Messages.getMessage("toAxisFault00"), exp);
1919            throw AxisFault.makeFault(exp);
1920        }
1921    }
1922
1923
1924    /** Register a Transport that should be used for URLs of the specified
1925     * protocol.
1926     *
1927     * Note: Not part of JAX-RPC specification.
1928     *
1929     * @param protocol the URL protocol (i.e. "tcp" for "tcp://" urls)
1930     * @param transportClass the class of a Transport type which will be used
1931     *                       for matching URLs.
1932     */
1933    public static void setTransportForProtocol(String protocol,
1934                                               Class transportClass) {
1935        if (Transport.class.isAssignableFrom(transportClass)) {
1936            transports.put(protocol, transportClass);
1937        }
1938        else {
1939            throw new InternalException(transportClass.toString());
1940        }
1941    }
1942
1943    /**
1944     * Set up the default transport URL mappings.
1945     *
1946     * This must be called BEFORE doing non-standard URL parsing (i.e. if you
1947     * want the system to accept a "local:" URL).  This is why the Options class
1948     * calls it before parsing the command-line URL argument.
1949     *
1950     * Note: Not part of JAX-RPC specification.
1951     */
1952    public static synchronized void initialize() {
1953        addTransportPackage("org.apache.axis.transport");
1954
1955        setTransportForProtocol("java",
1956                org.apache.axis.transport.java.JavaTransport.class);
1957        setTransportForProtocol("local",
1958                org.apache.axis.transport.local.LocalTransport.class);
1959        setTransportForProtocol("http", HTTPTransport.class);
1960        setTransportForProtocol("https", HTTPTransport.class);
1961    }
1962
1963    /**
1964     * Cache of transport packages we've already added to the system
1965     * property.
1966     */
1967    private static ArrayList transportPackages = null;
1968
1969    /** Add a package to the system protocol handler search path.  This
1970     * enables users to create their own URLStreamHandler classes, and thus
1971     * allow custom protocols to be used in Axis (typically on the client
1972     * command line).
1973     *
1974     * For instance, if you add "samples.transport" to the packages property,
1975     * and have a class samples.transport.tcp.Handler, the system will be able
1976     * to parse URLs of the form "tcp://host:port..."
1977     *
1978     * Note: Not part of JAX-RPC specification.
1979     *
1980     * @param packageName the package in which to search for protocol names.
1981     */
1982    public static synchronized void addTransportPackage(String packageName) {
1983        if (transportPackages == null) {
1984            transportPackages = new ArrayList();
1985            String currentPackages =
1986                    AxisProperties.getProperty(TRANSPORT_PROPERTY);
1987            if (currentPackages != null) {
1988                StringTokenizer tok = new StringTokenizer(currentPackages,
1989                                                          "|");
1990                while (tok.hasMoreTokens()) {
1991                    transportPackages.add(tok.nextToken());
1992                }
1993            }
1994        }
1995
1996        if (transportPackages.contains(packageName)) {
1997            return;
1998        }
1999
2000        transportPackages.add(packageName);
2001
2002        StringBuffer currentPackages = new StringBuffer();
2003        for (Iterator i = transportPackages.iterator(); i.hasNext();) {
2004            String thisPackage = (String) i.next();
2005            currentPackages.append(thisPackage);
2006            currentPackages.append('|');
2007        }
2008
2009        System.setProperty(TRANSPORT_PROPERTY, currentPackages.toString());
2010    }
2011
2012    /**
2013     * Convert the list of objects into RPCParam's based on the paramNames,
2014     * paramXMLTypes and paramModes variables.  If those aren't set then just
2015     * return what was passed in.
2016     *
2017     * @param  params   Array of parameters to pass into the operation/method
2018     * @return Object[] Array of parameters to pass to invoke()
2019     */
2020    private Object[] getParamList(Object[] params) {
2021        int  numParams = 0 ;
2022
2023        // If we never set-up any names... then just return what was passed in
2024        //////////////////////////////////////////////////////////////////////
2025        if (log.isDebugEnabled()) {
2026            log.debug( "operation=" + operation);
2027            if (operation != null) {
2028                log.debug("operation.getNumParams()=" +
2029                          operation.getNumParams());
2030            }
2031        }
2032        if ( operation == null || operation.getNumParams() == 0 ) {
2033            return( params );
2034        }
2035
2036        // Count the number of IN and INOUT params, this needs to match the
2037        // number of params passed in - if not throw an error
2038        /////////////////////////////////////////////////////////////////////
2039        numParams = operation.getNumInParams();
2040
2041        if ( params == null || numParams != params.length ) {
2042            throw new JAXRPCException(
2043                    Messages.getMessage(
2044                              "parmMismatch00",
2045                              (params == null) ? "no params" : "" + params.length, 
2046                              "" + numParams
2047                   ) 
2048           );
2049        }
2050
2051        log.debug( "getParamList number of params: " + params.length);
2052
2053        // All ok - so now produce an array of RPCParams
2054        //////////////////////////////////////////////////
2055        Vector result = new Vector();
2056        int    j = 0 ;
2057        ArrayList parameters = operation.getParameters();
2058
2059        for (int i = 0; i < parameters.size(); i++) {
2060            ParameterDesc param = (ParameterDesc)parameters.get(i);
2061            if (param.getMode() != ParameterDesc.OUT) {
2062                QName paramQName = param.getQName();
2063
2064                // Create an RPCParam if param isn't already an RPCParam.
2065                RPCParam rpcParam = null;
2066                Object p = params[j++];
2067                if(p instanceof RPCParam) {
2068                    rpcParam = (RPCParam)p;
2069                } else {
2070                    rpcParam = new RPCParam(paramQName.getNamespaceURI(),
2071                                            paramQName.getLocalPart(),
2072                                            p);
2073                }
2074                // Attach the ParameterDescription to the RPCParam
2075                // so that the serializer can use the (javaType, xmlType)
2076                // information.
2077                rpcParam.setParamDesc(param);
2078
2079                // Add the param to the header or vector depending
2080                // on whether it belongs in the header or body.
2081                if (param.isInHeader()) {
2082                    addHeader(new RPCHeaderParam(rpcParam));
2083                } else {
2084                    result.add(rpcParam);
2085                }
2086            }
2087        }
2088        return( result.toArray() );
2089    }
2090
2091    /**
2092     * Set the Transport
2093     *
2094     * Note: Not part of JAX-RPC specification.
2095     *
2096     * @param trans the Transport object we'll use to set up
2097     *                  MessageContext properties.
2098     */
2099    public void setTransport(Transport trans) {
2100        transport = trans;
2101        if (log.isDebugEnabled())
2102            log.debug(Messages.getMessage("transport00", "" + transport));
2103    }
2104
2105    /** Get the Transport registered for the given protocol.
2106     *
2107     * Note: Not part of JAX-RPC specification.
2108     *
2109     * @param protocol a protocol such as "http" or "local" which may
2110     *                 have a Transport object associated with it.
2111     * @return the Transport registered for this protocol, or null if none.
2112     */
2113    public Transport getTransportForProtocol(String protocol)
2114    {
2115        Class transportClass = (Class)transports.get(protocol);
2116        Transport ret = null;
2117        if (transportClass != null) {
2118            try {
2119                ret = (Transport)transportClass.newInstance();
2120            } catch (InstantiationException e) {
2121            } catch (IllegalAccessException e) {
2122            }
2123        }
2124        return ret;
2125    }
2126
2127    /**
2128     * Directly set the request message in our MessageContext.
2129     *
2130     * This allows custom message creation.
2131     *
2132     * Note: Not part of JAX-RPC specification.
2133     *
2134     * @param msg the new request message.
2135     * @throws RuntimeException containing the text of an AxisFault, if any
2136     * AxisFault was thrown
2137     */
2138    public void setRequestMessage(Message msg) {
2139         String attachformat= (String)getProperty(
2140           ATTACHMENT_ENCAPSULATION_FORMAT);
2141
2142         if(null != attachformat) {
2143              Attachments attachments=msg.getAttachmentsImpl();
2144              if(null != attachments) {
2145                  if( ATTACHMENT_ENCAPSULATION_FORMAT_MIME.equals(attachformat)) {
2146                    attachments.setSendType(Attachments.SEND_TYPE_MIME);
2147                  } else if ( ATTACHMENT_ENCAPSULATION_FORMAT_DIME.equals(attachformat)) {
2148                    attachments.setSendType(Attachments.SEND_TYPE_DIME);
2149                  }
2150              }
2151         }
2152
2153        if(null != attachmentParts && !attachmentParts.isEmpty()){
2154            try{
2155                Attachments attachments= msg.getAttachmentsImpl();
2156                if(null == attachments) {
2157                  throw new RuntimeException(
2158                          Messages.getMessage("noAttachments"));
2159                }
2160
2161                attachments.setAttachmentParts(attachmentParts);
2162            }catch(AxisFault ex){
2163              log.info(Messages.getMessage("axisFault00"), ex);
2164              throw new RuntimeException(ex.getMessage());
2165            }
2166        }
2167
2168        msgContext.setRequestMessage(msg);
2169        attachmentParts.clear();
2170    }
2171
2172    /**
2173     * Directly get the response message in our MessageContext.
2174     *
2175     * Shortcut for having to go thru the msgContext
2176     *
2177     * Note: Not part of JAX-RPC specification.
2178     *
2179     * @return the response Message object in the msgContext
2180     */
2181    public Message getResponseMessage() {
2182        return msgContext.getResponseMessage();
2183    }
2184
2185    /**
2186     * Obtain a reference to our MessageContext.
2187     *
2188     * Note: Not part of JAX-RPC specification.
2189     *
2190     * @return the MessageContext.
2191     */
2192    public MessageContext getMessageContext () {
2193        return msgContext;
2194    }
2195
2196    /**
2197     * Add a header which should be inserted into each outgoing message
2198     * we generate.
2199     *
2200     * Note: Not part of JAX-RPC specification.
2201     *
2202     * @param header a SOAPHeaderElement to be inserted into messages
2203     */
2204    public void addHeader(SOAPHeaderElement header)
2205    {
2206        if (myHeaders == null) {
2207            myHeaders = new Vector();
2208        }
2209        myHeaders.add(header);
2210    }
2211
2212    /**
2213     * Clear the list of headers which we insert into each message
2214     *
2215     * Note: Not part of JAX-RPC specification.
2216     */
2217    public void clearHeaders()
2218    {
2219        myHeaders = null;
2220    }
2221
2222    public TypeMapping getTypeMapping()
2223    {
2224        // Get the TypeMappingRegistry
2225        TypeMappingRegistry tmr = msgContext.getTypeMappingRegistry();
2226
2227        // If a TypeMapping is not available, add one.
2228        return tmr.getOrMakeTypeMapping(getEncodingStyle());
2229    }
2230
2231    /**
2232     * Register type mapping information for serialization/deserialization
2233     *
2234     * Note: Not part of JAX-RPC specification.
2235     *
2236     * @param javaType is  the Java class of the data type.
2237     * @param xmlType the xsi:type QName of the associated XML type.
2238     * @param sf/df are the factories (or the Class objects of the factory).
2239     */
2240    public void registerTypeMapping(Class javaType, QName xmlType,
2241                                    SerializerFactory sf,
2242                                    DeserializerFactory df) {
2243        registerTypeMapping(javaType, xmlType, sf, df, true);
2244    }
2245
2246    /**
2247     * Register type mapping information for serialization/deserialization
2248     *
2249     * Note: Not part of JAX-RPC specification.
2250     *
2251     * @param javaType is  the Java class of the data type.
2252     * @param xmlType the xsi:type QName of the associated XML type.
2253     * @param sf/df are the factories (or the Class objects of the factory).
2254     * @param force Indicates whether to add the information if already registered.
2255     */
2256    public void registerTypeMapping(Class javaType, QName xmlType,
2257                                    SerializerFactory sf,
2258                                    DeserializerFactory df,
2259                                    boolean force) {
2260        TypeMapping tm = getTypeMapping();
2261        if (!force && tm.isRegistered(javaType, xmlType)) {
2262            return;
2263        }
2264
2265        // Register the information
2266        tm.register(javaType, xmlType, sf, df);
2267    }
2268
2269    /**
2270     * register this type matting
2271     * @param javaType
2272     * @param xmlType
2273     * @param sfClass
2274     * @param dfClass
2275     */
2276    public void registerTypeMapping(Class javaType, QName xmlType,
2277                                    Class sfClass, Class dfClass) {
2278        registerTypeMapping(javaType, xmlType, sfClass, dfClass, true);
2279    }
2280
2281    /**
2282     * register a type. This only takes place if either the serializer or
2283     * deserializer factory could be created.
2284     * @param javaType java type to handle
2285     * @param xmlType XML mapping
2286     * @param sfClass class of serializer factory
2287     * @param dfClass class of deserializer factory
2288     * @param force
2289     */
2290    public void registerTypeMapping(Class javaType,
2291                                    QName xmlType,
2292                                    Class sfClass,
2293                                    Class dfClass,
2294                                    boolean force) {
2295        // Instantiate the factory using introspection.
2296        SerializerFactory   sf =
2297                BaseSerializerFactory.createFactory(sfClass, javaType, xmlType);
2298        DeserializerFactory df =
2299                BaseDeserializerFactory.createFactory(dfClass,
2300                                                      javaType,
2301                                                      xmlType);
2302        if (sf != null || df != null) {
2303            registerTypeMapping(javaType, xmlType, sf, df, force);
2304        }
2305    }
2306
2307    /************************************************
2308     * Invocation
2309     */
2310
2311    /** Invoke an RPC service with a method name and arguments.
2312     *
2313     * This will call the service, serializing all the arguments, and
2314     * then deserialize the return value.
2315     *
2316     * Note: Not part of JAX-RPC specification.
2317     *
2318     * @param namespace the desired namespace URI of the method element
2319     * @param method the method name
2320     * @param args an array of Objects representing the arguments to the
2321     *             invoked method.  If any of these objects are RPCParams,
2322     *             Axis will use the embedded name of the RPCParam as the
2323     *             name of the parameter.  Otherwise, we will serialize
2324     *             each argument as an XML element called "arg<n>".
2325     * @return a deserialized Java Object containing the return value
2326     * @exception AxisFault
2327     */
2328    public Object invoke(String namespace, String method, Object[] args)
2329                    throws AxisFault {
2330
2331        if (log.isDebugEnabled()) {
2332            log.debug("Enter: Call::invoke(ns, meth, args)");
2333        }
2334
2335        /**
2336         * Since JAX-RPC requires us to specify all or nothing, if setReturnType
2337         * was called (returnType != null) and we have args but addParameter
2338         * wasn't called (paramXMLTypes == null), then toss a fault.
2339         */
2340        if (getReturnType() != null && args != null && args.length != 0
2341                && operation.getNumParams() == 0) {
2342            throw new AxisFault(Messages.getMessage("mustSpecifyParms"));
2343        }
2344
2345        RPCElement body = new RPCElement(namespace, method, getParamList(args));
2346
2347        Object ret = invoke( body );
2348
2349        if (log.isDebugEnabled()) {
2350            log.debug("Exit: Call::invoke(ns, meth, args)");
2351        }
2352
2353        return ret;
2354    }
2355
2356    /** Convenience method to invoke a method with a default (empty)
2357     * namespace.  Calls invoke() above.
2358     *
2359     * Note: Not part of JAX-RPC specification.
2360     *
2361     * @param method the method name
2362     * @param args an array of Objects representing the arguments to the
2363     *             invoked method.  If any of these objects are RPCParams,
2364     *             Axis will use the embedded name of the RPCParam as the
2365     *             name of the parameter.  Otherwise, we will serialize
2366     *             each argument as an XML element called "arg<n>".
2367     * @return a deserialized Java Object containing the return value
2368     * @exception AxisFault
2369     */
2370    public Object invoke( String method, Object [] args ) throws AxisFault
2371    {
2372        return invoke("", method, args);
2373    }
2374
2375    /** Invoke an RPC service with a pre-constructed RPCElement.
2376     *
2377     * Note: Not part of JAX-RPC specification.
2378     *
2379     * @param body an RPCElement containing all the information about
2380     *             this call.
2381     * @return a deserialized Java Object containing the return value
2382     * @exception AxisFault
2383     */
2384    public Object invoke( RPCElement body ) throws AxisFault {
2385        if (log.isDebugEnabled()) {
2386            log.debug("Enter: Call::invoke(RPCElement)");
2387        }
2388
2389        /**
2390         * Since JAX-RPC requires us to specify a return type if we've set
2391         * parameter types, check for this case right now and toss a fault
2392         * if things don't look right.
2393         */
2394        if (!invokeOneWay && operation != null &&
2395                operation.getNumParams() > 0 && getReturnType() == null) {
2396            // TCK:
2397            // Issue an error if the return type was not set, but continue processing.
2398            //throw new AxisFault(Messages.getMessage("mustSpecifyReturnType"));
2399            log.error(Messages.getMessage("mustSpecifyReturnType"));
2400        }
2401
2402        SOAPEnvelope         reqEnv =
2403                new SOAPEnvelope(msgContext.getSOAPConstants(),
2404                                 msgContext.getSchemaVersion());
2405        SOAPEnvelope         resEnv = null ;
2406        Message              reqMsg = new Message( reqEnv );
2407        Message              resMsg = null ;
2408        Vector               resArgs = null ;
2409        Object               result = null ;
2410
2411        // Clear the output params
2412        outParams = new HashMap();
2413        outParamsList = new ArrayList();
2414
2415        // Set both the envelope and the RPCElement encoding styles
2416        try {
2417            body.setEncodingStyle(getEncodingStyle());
2418
2419            setRequestMessage(reqMsg);
2420
2421            reqEnv.addBodyElement(body);
2422            reqEnv.setMessageType(Message.REQUEST);
2423
2424            invoke();
2425        } catch (Exception e) {
2426            entLog.debug(Messages.getMessage("toAxisFault00"), e);
2427            throw AxisFault.makeFault(e);
2428        }
2429
2430        resMsg = msgContext.getResponseMessage();
2431
2432        if (resMsg == null) {
2433          if (msgContext.isPropertyTrue(FAULT_ON_NO_RESPONSE, false)) {
2434            throw new AxisFault(Messages.getMessage("nullResponse00"));
2435          } else {
2436            return null;
2437          }
2438        }
2439
2440        resEnv = resMsg.getSOAPEnvelope();
2441        SOAPBodyElement bodyEl = resEnv.getFirstBody();
2442        if (bodyEl == null) {
2443            return null;
2444        }
2445
2446        if (bodyEl instanceof RPCElement) {
2447            try {
2448                resArgs = ((RPCElement) bodyEl).getParams();
2449            } catch (Exception e) {
2450                log.error(Messages.getMessage("exception00"), e);
2451                throw AxisFault.makeFault(e);
2452            }
2453
2454            if (resArgs != null && resArgs.size() > 0) {
2455
2456                // If there is no return, then we start at index 0 to create the outParams Map.
2457                // If there IS a return, then we start with 1.
2458                int outParamStart = 0;
2459
2460                // If we have resArgs and the returnType is specified, then the first
2461                // resArgs is the return.  If we have resArgs and neither returnType
2462                // nor paramXMLTypes are specified, then we assume that the caller is
2463                // following the non-JAX-RPC AXIS shortcut of not having to specify
2464                // the return, in which case we again assume the first resArgs is
2465                // the return.
2466                // NOTE 1:  the non-JAX-RPC AXIS shortcut allows a potential error
2467                // to escape notice.  If the caller IS NOT following the non-JAX-RPC
2468                // shortcut but instead intentionally leaves returnType and params
2469                // null (ie., a method that takes no parameters and returns nothing)
2470                // then, if we DO receive something it should be an error, but this
2471                // code passes it through.  The ideal solution here is to require
2472                // this caller to set the returnType to void, but there's no void
2473                // type in XML.
2474                // NOTE 2:  we should probably verify that the resArgs element
2475                // types match the expected returnType and paramXMLTypes, but I'm not
2476                // sure how to do that since the resArgs value is a Java Object
2477                // and the returnType and paramXMLTypes are QNames.
2478
2479                // GD 03/15/02 : We're now checking for invalid metadata
2480                // config at the top of this method, so don't need to do it
2481                // here.  Check for void return, though.
2482
2483                boolean findReturnParam = false;
2484                QName returnParamQName = null;
2485                if (operation != null) {
2486                    returnParamQName = operation.getReturnQName();
2487                }
2488
2489                if (!XMLType.AXIS_VOID.equals(getReturnType())) {
2490                    if (returnParamQName == null) {
2491                        // Assume the first param is the return
2492                        RPCParam param = (RPCParam)resArgs.get(0);
2493                        result = param.getObjectValue();
2494                        outParamStart = 1;
2495                    } else {
2496                        // If the QName of the return value was given to us, look
2497                        // through the result arguments to find the right name
2498                        findReturnParam = true;
2499                    }
2500                }
2501
2502                // The following loop looks at the resargs and
2503                // converts the value to the appropriate return/out parameter
2504                // value.  If the return value is found, is value is
2505                // placed in result.  The remaining resargs are
2506                // placed in the outParams list (note that if a resArg
2507                // is found that does not match a operation parameter qname,
2508                // it is still placed in the outParms list).
2509                for (int i = outParamStart; i < resArgs.size(); i++) {
2510                    RPCParam param = (RPCParam) resArgs.get(i);
2511
2512                    Class javaType = getJavaTypeForQName(param.getQName());
2513                    Object value = param.getObjectValue();
2514
2515                    // Convert type if needed
2516                    if (javaType != null && value != null &&
2517                           !javaType.isAssignableFrom(value.getClass())) {
2518                        value = JavaUtils.convert(value, javaType);
2519                    }
2520
2521                    // Check if this parameter is our return
2522                    // otherwise just add it to our outputs
2523                    if (findReturnParam &&
2524                          returnParamQName.equals(param.getQName())) {
2525                        // found it!
2526                        result = value;
2527                        findReturnParam = false;
2528                    } else {
2529                        outParams.put(param.getQName(), value);
2530                        outParamsList.add(value);
2531                    }
2532                }
2533
2534                // added by scheu:
2535                // If the return param is still not found, that means
2536                // the returned value did not have the expected qname.
2537                // The soap specification indicates that this should be
2538                // accepted (and we also fail interop tests if we are strict here).
2539                // Look through the outParms and find one that
2540                // does not match one of the operation parameters.
2541                if (findReturnParam) {
2542                    Iterator it = outParams.keySet().iterator();
2543                    while (it.hasNext() && findReturnParam) {
2544                        QName qname = (QName) it.next();
2545                        ParameterDesc paramDesc =
2546                            operation.getOutputParamByQName(qname);
2547                        if (paramDesc == null) {
2548                            // Doesn't match a paramter, so use this for the return
2549                            findReturnParam = false;
2550                            result = outParams.remove(qname);
2551                        }
2552                    }
2553                }
2554
2555                // If we were looking for a particular QName for the return and
2556                // still didn't find it, throw an exception
2557                if (findReturnParam) {
2558                    String returnParamName = returnParamQName.toString();
2559                    throw new AxisFault(Messages.getMessage("noReturnParam",
2560                                                            returnParamName));
2561                }
2562            }
2563        } else {
2564            // This is a SOAPBodyElement, try to treat it like a return value
2565            try {
2566                result = bodyEl.getValueAsType(getReturnType());
2567            } catch (Exception e) {
2568                // just return the SOAPElement
2569                result = bodyEl;
2570            }
2571
2572        }
2573
2574        if (log.isDebugEnabled()) {
2575            log.debug("Exit: Call::invoke(RPCElement)");
2576        }
2577
2578        // Convert type if needed
2579        if (operation != null && operation.getReturnClass() != null) {
2580            result = JavaUtils.convert(result, operation.getReturnClass());
2581        }
2582
2583        return( result );
2584    }
2585
2586    /**
2587     * Get the javaType for a given parameter.
2588     *
2589     * @param name  the QName of the parameter
2590     * @return the class associated with that parameter
2591     */
2592    private Class getJavaTypeForQName(QName name) {
2593        if (operation == null) {
2594            return null;
2595        }
2596        ParameterDesc param = operation.getOutputParamByQName(name);
2597        return param == null ? null : param.getJavaType();
2598    }
2599
2600    /**
2601     * Set engine option.
2602     *
2603     * Note: Not part of JAX-RPC specification.
2604     */
2605    public void setOption(String name, Object value) {
2606        service.getEngine().setOption(name, value);
2607    }
2608
2609    /**
2610     * Invoke this Call with its established MessageContext
2611     * (perhaps because you called this.setRequestMessage())
2612     *
2613     * Note: Not part of JAX-RPC specification.
2614     *
2615     * @exception AxisFault
2616     */
2617    public void invoke() throws AxisFault {
2618        if (log.isDebugEnabled()) {
2619            log.debug("Enter: Call::invoke()");
2620        }
2621
2622        isNeverInvoked  = false;
2623
2624        Message      reqMsg  = null ;
2625        SOAPEnvelope reqEnv  = null ;
2626
2627        msgContext.reset();
2628        msgContext.setResponseMessage(null);
2629        msgContext.setProperty( MessageContext.CALL, this );
2630        msgContext.setProperty( WSDL_SERVICE, service );
2631        msgContext.setProperty( WSDL_PORT_NAME, getPortName() );
2632        if ( isMsg ) {
2633            msgContext.setProperty( MessageContext.IS_MSG, "true" );
2634        }
2635
2636        if (username != null) {
2637            msgContext.setUsername(username);
2638        }
2639        if (password != null) {
2640            msgContext.setPassword(password);
2641        }
2642        msgContext.setMaintainSession(maintainSession);
2643
2644        if (operation != null) {
2645            msgContext.setOperation(operation);
2646            operation.setStyle(getOperationStyle());
2647            operation.setUse(getOperationUse());
2648        }
2649
2650        if (useSOAPAction) {
2651            msgContext.setUseSOAPAction(true);
2652        }
2653        if (SOAPActionURI != null) {
2654            msgContext.setSOAPActionURI(SOAPActionURI);
2655        } else {
2656            msgContext.setSOAPActionURI(null);
2657        }
2658        if (timeout != null) {
2659            msgContext.setTimeout(timeout.intValue());
2660        }
2661        msgContext.setHighFidelity(!useStreaming);
2662
2663        // Determine client target service
2664        if (myService != null) {
2665            // If we have a SOAPService kicking around, use that directly
2666            msgContext.setService(myService);
2667        } else {
2668            if (portName != null) {
2669                // No explicit service.  If we have a target service name,
2670                // try that.
2671                msgContext.setTargetService(portName.getLocalPart());
2672            } else {
2673                // No direct config, so try the namespace of the first body.
2674                reqMsg = msgContext.getRequestMessage();
2675                
2676                boolean isStream = ((SOAPPart)reqMsg.getSOAPPart()).isBodyStream();
2677                
2678                if (reqMsg != null && !isStream) {
2679                    reqEnv = reqMsg.getSOAPEnvelope();
2680
2681                    SOAPBodyElement body = reqEnv.getFirstBody();
2682
2683                    if (body != null) {
2684                        if ( body.getNamespaceURI() == null ) {
2685                            throw new AxisFault("Call.invoke",
2686                                                Messages.getMessage("cantInvoke00", body.getName()),
2687                                                null, null);
2688                        } else {
2689                            msgContext.setTargetService(body.getNamespaceURI());
2690                        }
2691                    }
2692                }
2693            }
2694        }
2695        if (log.isDebugEnabled()) {
2696            log.debug(Messages.getMessage("targetService",
2697                    msgContext.getTargetService()));
2698        }
2699
2700        Message requestMessage = msgContext.getRequestMessage();
2701        if (requestMessage != null) {
2702            try {
2703                msgContext.setProperty(SOAPMessage.CHARACTER_SET_ENCODING, requestMessage.getProperty(SOAPMessage.CHARACTER_SET_ENCODING));
2704            } catch (SOAPException e) {
2705            }
2706            
2707            if(myHeaders != null) {
2708                reqEnv = requestMessage.getSOAPEnvelope();
2709    
2710                // If we have headers to insert, do so now.
2711                for (int i = 0 ; myHeaders != null && i < myHeaders.size() ; i++ ) {
2712                    reqEnv.addHeader((SOAPHeaderElement)myHeaders.get(i));
2713                }
2714            }
2715        }
2716
2717        // set up transport if there is one
2718        if (transport != null) {
2719            transport.setupMessageContext(msgContext, this, service.getEngine());
2720        }
2721        else {
2722            msgContext.setTransportName( transportName );
2723        }
2724
2725        SOAPService svc = msgContext.getService();
2726        if (svc != null) {
2727            svc.setPropertyParent(myProperties);
2728        } else {
2729            msgContext.setPropertyParent(myProperties);
2730        }
2731
2732        // For debugging - print request message
2733        if (log.isDebugEnabled()) {
2734            StringWriter writer = new StringWriter();
2735            try {
2736                SerializationContext ctx = new SerializationContext(writer,
2737                                                                   msgContext);
2738                requestMessage.getSOAPEnvelope().output(ctx);
2739                writer.close();
2740            } catch (Exception e) {
2741                throw AxisFault.makeFault(e);
2742            } finally {
2743                log.debug(writer.getBuffer().toString());
2744            }
2745        }
2746
2747        if(!invokeOneWay) {
2748            invokeEngine(msgContext);
2749        } else {
2750            invokeEngineOneWay(msgContext);
2751        }
2752
2753        if (log.isDebugEnabled()) {
2754            log.debug("Exit: Call::invoke()");
2755        }
2756    }
2757
2758    /**
2759     * Invoke the message on the current engine and do not wait for a response.
2760     *
2761     * @param msgContext  the <code>MessageContext</code> to use
2762     * @throws AxisFault if the invocation raised a fault
2763     */
2764    private void invokeEngine(MessageContext msgContext) throws AxisFault {
2765        service.getEngine().invoke( msgContext );
2766
2767        if (transport != null) {
2768            transport.processReturnedMessageContext(msgContext);
2769        }
2770
2771        Message resMsg = msgContext.getResponseMessage();
2772
2773        if (resMsg == null) {
2774          if (msgContext.isPropertyTrue(FAULT_ON_NO_RESPONSE, false)) {
2775            throw new AxisFault(Messages.getMessage("nullResponse00"));
2776          } else {
2777            return;
2778          }
2779        }
2780
2781        /** This must happen before deserialization...
2782         */
2783        resMsg.setMessageType(Message.RESPONSE);
2784
2785        SOAPEnvelope resEnv = resMsg.getSOAPEnvelope();
2786
2787        SOAPBodyElement respBody = resEnv.getFirstBody();
2788        if (respBody instanceof SOAPFault) {
2789            //we got a fault
2790            if(operation == null ||
2791                    operation.getReturnClass() == null ||
2792                    operation.getReturnClass() !=
2793                        javax.xml.soap.SOAPMessage.class) {
2794                //unless we don't care about the return value or we want
2795                //a raw message back
2796                //get the fault from the body and throw it
2797                throw ((SOAPFault)respBody).getFault();
2798            }
2799        }
2800    }
2801
2802    /**
2803     * Implement async invocation by running the request in a new thread
2804     * @param msgContext
2805     */
2806    private void invokeEngineOneWay(final MessageContext msgContext) {
2807        //TODO: this is not a good way to do stuff, as it has no error reporting facility
2808        //create a new class
2809        Runnable runnable = new Runnable(){
2810            public void run() {
2811                msgContext.setProperty(Call.ONE_WAY, Boolean.TRUE);
2812                try {
2813                    service.getEngine().invoke( msgContext );
2814                } catch (AxisFault af){
2815                    //TODO: handle errors properly
2816                    log.debug(Messages.getMessage("exceptionPrinting"), af);
2817                }
2818                msgContext.removeProperty(Call.ONE_WAY);
2819            }
2820        };
2821        //create a thread to run it
2822        Thread thread = new Thread(runnable);
2823        //run it
2824        thread.start();
2825    }
2826
2827    /**
2828     * Get the output parameters (if any) from the last invocation.
2829     * 
2830     * This allows named access - if you need sequential access, use
2831     * getOutputValues().
2832     *
2833     * @return a Map containing the output parameter values, indexed by QName
2834     */
2835    public Map getOutputParams()
2836    {
2837        if (isNeverInvoked) {
2838            throw new JAXRPCException(
2839                    Messages.getMessage("outputParamsUnavailable"));
2840        }
2841        return this.outParams;
2842    }
2843
2844    /**
2845     * Returns a List values for the output parameters of the last
2846     * invoked operation.
2847     *
2848     * @return Values for the output parameters. An empty List is
2849     *         returned if there are no output values.
2850     *
2851     * @throws JAXRPCException - If this method is invoked for a
2852     *                           one-way operation or is invoked
2853     *                           before any invoke method has been called.
2854     */
2855    public List getOutputValues() {
2856        if (isNeverInvoked) {
2857            throw new JAXRPCException(
2858                    Messages.getMessage("outputParamsUnavailable"));
2859        }
2860        return outParamsList;
2861    }
2862
2863    /**
2864     * Get the Service object associated with this Call object.
2865     *
2866     * Note: Not part of JAX-RPC specification.
2867     *
2868     * @return Service the Service object this Call object is associated with
2869     */
2870    public Service getService()
2871    {
2872        return this.service;
2873    }
2874
2875    /**
2876     *
2877     * Set the service so that it defers missing property gets to the
2878     * Call.  So when client-side Handlers get at the MessageContext,
2879     * the property scoping will be MC -> SOAPService -> Call
2880     */
2881    public void setSOAPService(SOAPService service)
2882    {
2883        myService = service;
2884        if (service != null) {
2885            // Set the service so that it defers missing property gets to the
2886            // Call.  So when client-side Handlers get at the MessageContext,
2887            // the property scoping will be MC -> SOAPService -> Call -> Engine
2888            
2889            // THE ORDER OF THESE TWO CALLS IS IMPORTANT, since setting the
2890            // engine on a service will set the property parent for the service
2891            service.setEngine(this.service.getAxisClient());
2892            service.setPropertyParent(myProperties);
2893        }
2894    }
2895
2896    /**
2897     * Sets the client-side request and response Handlers.  This is handy
2898     * for programatically setting up client-side work without deploying
2899     * via WSDD or the EngineConfiguration mechanism.
2900     */
2901    public void setClientHandlers(Handler reqHandler, Handler respHandler)
2902    {
2903        // Create a SOAPService which will be used as the client-side service
2904        // handler.
2905        setSOAPService(new SOAPService(reqHandler, null, respHandler));
2906    }
2907
2908
2909    /**
2910     * This method adds an attachment.
2911     * <p>
2912     * Note: Not part of JAX-RPC specification.
2913     *
2914     * @param attachment the <code>Object</code> to attach
2915     * @exception RuntimeException if there is no support for attachments
2916     *
2917     */
2918     public void addAttachmentPart( Object attachment){
2919         attachmentParts.add(attachment);
2920     }
2921
2922    /**
2923     * Add a fault for this operation.
2924     * <p>
2925     * Note: Not part of JAX-RPC specificaion.
2926     *
2927     * @param qname     qname of the fault
2928     * @param cls       class of the fault
2929     * @param xmlType   XML type of the fault
2930     * @param isComplex true if xmlType is a complex type, false otherwise
2931     */
2932    public void addFault(QName qname, Class cls,
2933                         QName xmlType, boolean isComplex) {
2934        if (operationSetManually) {
2935            throw new RuntimeException(
2936                    Messages.getMessage("operationAlreadySet"));
2937        }
2938
2939        if (operation == null) {
2940            operation = new OperationDesc();
2941        }
2942
2943        FaultDesc fault = new FaultDesc();
2944        fault.setQName(qname);
2945        fault.setClassName(cls.getName());
2946        fault.setXmlType(xmlType);
2947        fault.setComplex(isComplex);
2948        operation.addFault(fault);
2949    }
2950
2951    /**
2952     * Hand a complete OperationDesc to the Call, and note that this was
2953     * done so that others don't try to mess with it by calling addParameter,
2954     * setReturnType, etc.
2955     *
2956     * @param operation the OperationDesc to associate with this call.
2957     */
2958    public void setOperation(OperationDesc operation) {
2959        this.operation = operation;
2960        operationSetManually = true;
2961    }
2962
2963    public OperationDesc getOperation()
2964    {
2965        return operation;
2966    }
2967
2968    public void clearOperation() {
2969        operation = null;
2970        operationSetManually = false;
2971    }
2972}