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