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}