1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 package org.apache.axis2.client;
21
22 import org.apache.axiom.om.OMAbstractFactory;
23 import org.apache.axiom.om.OMElement;
24 import org.apache.axiom.soap.SOAP12Constants;
25 import org.apache.axiom.soap.SOAPEnvelope;
26 import org.apache.axiom.soap.SOAPFactory;
27 import org.apache.axiom.soap.SOAPHeader;
28 import org.apache.axiom.soap.SOAPHeaderBlock;
29 import org.apache.axis2.AxisFault;
30 import org.apache.axis2.addressing.EndpointReference;
31 import org.apache.axis2.client.async.AxisCallback;
32 import org.apache.axis2.client.async.Callback;
33 import org.apache.axis2.context.ConfigurationContext;
34 import org.apache.axis2.context.ConfigurationContextFactory;
35 import org.apache.axis2.context.MessageContext;
36 import org.apache.axis2.context.OperationContext;
37 import org.apache.axis2.context.ServiceContext;
38 import org.apache.axis2.context.ServiceGroupContext;
39 import org.apache.axis2.description.AxisModule;
40 import org.apache.axis2.description.AxisOperation;
41 import org.apache.axis2.description.AxisService;
42 import org.apache.axis2.description.AxisServiceGroup;
43 import org.apache.axis2.description.OutInAxisOperation;
44 import org.apache.axis2.description.OutOnlyAxisOperation;
45 import org.apache.axis2.description.Parameter;
46 import org.apache.axis2.description.RobustOutOnlyAxisOperation;
47 import org.apache.axis2.description.TransportOutDescription;
48 import org.apache.axis2.engine.AxisConfiguration;
49 import org.apache.axis2.engine.ListenerManager;
50 import org.apache.axis2.i18n.Messages;
51 import org.apache.axis2.namespace.Constants;
52 import org.apache.axis2.util.Counter;
53 import org.apache.axis2.wsdl.WSDLConstants;
54 import org.apache.commons.logging.Log;
55 import org.apache.commons.logging.LogFactory;
56
57 import javax.wsdl.Definition;
58 import javax.xml.namespace.QName;
59 import java.net.URL;
60 import java.util.ArrayList;
61
62 /**
63 * Client access to a service. Each instance of this class is associated with a particular {@link
64 * org.apache.axis2.description.AxisService}, and the methods support operations using that service.
65 * {@link Options} instances are used to configure various aspects of the service access.
66 */
67 public class ServiceClient {
68 protected static final Log log = LogFactory.getLog(ServiceClient.class);
69
70 /** Base name used for a service created without an existing configuration. */
71 public static final String ANON_SERVICE = "anonService";
72
73 /** Counter used to generate the anonymous service name. */
74 private static Counter anonServiceCounter = new Counter();
75
76 /**
77 * Operation name used for an anonymous out-only operation (meaning we send a message with no
78 * response allowed from the service, equivalent to a WSDL In-Only operation).
79 */
80 public static final QName ANON_OUT_ONLY_OP = new QName(
81 Constants.AXIS2_NAMESPACE_URI, "anonOutonlyOp", Constants.AXIS2_NAMESPACE_PREFIX);
82
83 /**
84 * Operation name used for an anonymous robust-out-only operation (meaning we send a message,
85 * with the only possible response a fault, equivalent to a WSDL Robust-In-Only operation).
86 */
87 public static final QName ANON_ROBUST_OUT_ONLY_OP = new QName(
88 Constants.AXIS2_NAMESPACE_URI, "anonRobustOp", Constants.AXIS2_NAMESPACE_PREFIX);
89
90 /**
91 * Operation name used for an anonymous in-out operation (meaning we sent a message and receive
92 * a response, equivalent to a WSDL In-Out operation).
93 */
94 public static final QName ANON_OUT_IN_OP = new QName(Constants.AXIS2_NAMESPACE_URI,
95 "anonOutInOp",
96 Constants.AXIS2_NAMESPACE_PREFIX);
97
98 // the meta-data of the service that this client access
99 private AxisService axisService;
100
101 // the configuration in which my meta-data lives
102 private AxisConfiguration axisConfig;
103
104 // the configuration context in which I live
105 private ConfigurationContext configContext;
106
107 // service context for this specific service instance
108 private ServiceContext serviceContext;
109
110 // client options for this service interaction
111 private Options options = new Options();
112
113 // options that must override those of the child operation client also
114 private Options overrideOptions;
115
116 // list of headers to be sent with the simple APIs
117 private ArrayList<OMElement> headers;
118
119 //whether we create configctx or not
120 private boolean createConfigCtx;
121
122 private int hashCode;
123
124 private boolean removeAxisService;
125
126 /**
127 * Create a service client configured to work with a specific AxisService. If this service is
128 * already in the world that's handed in (in the form of a ConfigurationContext) then I will
129 * happily work in it. If not I will create a small little virtual world and live there.
130 *
131 * @param configContext The configuration context under which this service lives (may be null,
132 * in which case a new local one will be created)
133 * @param axisService The service for which this is the client (may be <code>null</code>, in
134 * which case an anonymous service will be created)
135 * @throws AxisFault if something goes wrong while creating a config context (if needed)
136 */
137 public ServiceClient(ConfigurationContext configContext,
138 AxisService axisService) throws AxisFault {
139 configureServiceClient(configContext, axisService);
140 }
141
142 private void configureServiceClient(ConfigurationContext configContext, AxisService axisService)
143 throws AxisFault {
144 if (configContext == null) {
145 if (ListenerManager.defaultConfigurationContext == null) {
146 configContext = ConfigurationContextFactory.
147 createConfigurationContextFromFileSystem(null, null);
148 ListenerManager.defaultConfigurationContext = configContext;
149 createConfigCtx = true;
150 } else {
151 configContext = ListenerManager.defaultConfigurationContext;
152 }
153 }
154 this.configContext = configContext;
155 hashCode = (int)anonServiceCounter.incrementAndGet();
156
157 // Initialize transports
158 ListenerManager transportManager = configContext.getListenerManager();
159 if (transportManager == null) {
160 transportManager = new ListenerManager();
161 transportManager.init(this.configContext);
162 }
163
164 // save the axisConfig and service
165 axisConfig = configContext.getAxisConfiguration();
166
167 if (axisService == null) {
168 axisService = createAnonymousService();
169 }
170 this.axisService = axisService;
171 // axis service is removed from the configuration context
172 // only if user has not added it to configuration context.
173 if (axisConfig.getService(axisService.getName()) == null) {
174 axisService.setClientSide(true);
175 axisConfig.addService(axisService);
176 removeAxisService = true;
177 } else {
178 axisService.setClientSide(true);
179 removeAxisService = false;
180 }
181 AxisServiceGroup axisServiceGroup = axisService.getAxisServiceGroup();
182 ServiceGroupContext sgc = configContext.createServiceGroupContext(axisServiceGroup);
183 serviceContext = sgc.getServiceContext(axisService);
184 }
185
186
187 /**
188 * This is WSDL4J based constructor to configure the Service Client/ TODO: make this policy
189 * aware
190 *
191 * @param configContext active ConfigurationContext
192 * @param wsdl4jDefinition the WSDL we're going to be using to configure ourselves
193 * @param wsdlServiceName QName of the WSDL service we'd like to access
194 * @param portName name of the WSDL port we'd like to access
195 * @throws AxisFault in case of error
196 */
197
198 public ServiceClient(ConfigurationContext configContext, Definition wsdl4jDefinition,
199 QName wsdlServiceName, String portName) throws AxisFault {
200 configureServiceClient(configContext, AxisService.createClientSideAxisService(
201 wsdl4jDefinition, wsdlServiceName, portName, options));
202 }
203
204 /**
205 * Create a service client for WSDL service identified by the QName of the wsdl:service element
206 * in a WSDL document.
207 *
208 * @param configContext The configuration context under which this service lives (may be
209 * <code>null</code>, in which case a new local one will be created) *
210 * @param wsdlURL The URL of the WSDL document to read
211 * @param wsdlServiceName The QName of the WSDL service in the WSDL document to create a client
212 * for
213 * @param portName The name of the WSDL 1.1 port to create a client for. May be null (if
214 * WSDL 2.0 is used or if only one port is there). .
215 * @throws AxisFault if something goes wrong while creating a config context (if needed)
216 */
217 public ServiceClient(ConfigurationContext configContext, URL wsdlURL,
218 QName wsdlServiceName, String portName) throws AxisFault {
219 configureServiceClient(configContext, AxisService.createClientSideAxisService(wsdlURL,
220 wsdlServiceName,
221 portName,
222 options));
223 Parameter transportName = axisService.getParameter("TRANSPORT_NAME");
224 if (transportName != null) {
225 TransportOutDescription transportOut =
226 configContext.getAxisConfiguration().getTransportOut(
227 transportName.getValue().toString());
228 if (transportOut == null) {
229 throw new AxisFault(
230 "Cannot load transport from binding, either defin in Axis2.config " +
231 "or set it explicitely in ServiceClinet.Options");
232 } else {
233 options.setTransportOut(transportOut);
234 }
235 }
236 }
237
238 /**
239 * Create a service client by assuming an anonymous service and any other necessary
240 * information.
241 *
242 * @throws AxisFault in case of error
243 */
244 public ServiceClient() throws AxisFault {
245 this(null, null);
246 }
247
248 /**
249 * Create an anonymous axisService with one (anonymous) operation for each MEP that we support
250 * dealing with anonymously using the convenience APIs.
251 *
252 * @return the minted anonymous service
253 */
254 private AxisService createAnonymousService() {
255 // now add anonymous operations to the axis2 service for use with the
256 // shortcut client API. NOTE: We only add the ones we know we'll use
257 // later in the convenience API; if you use
258 // this constructor then you can't expect any magic!
259 AxisService axisService =
260 new AxisService(ANON_SERVICE + anonServiceCounter.incrementAndGet());
261 RobustOutOnlyAxisOperation robustoutoonlyOperation = new RobustOutOnlyAxisOperation(
262 ANON_ROBUST_OUT_ONLY_OP);
263 axisService.addOperation(robustoutoonlyOperation);
264
265 OutOnlyAxisOperation outOnlyOperation = new OutOnlyAxisOperation(
266 ANON_OUT_ONLY_OP);
267 axisService.addOperation(outOnlyOperation);
268
269 OutInAxisOperation outInOperation = new OutInAxisOperation(
270 ANON_OUT_IN_OP);
271 axisService.addOperation(outInOperation);
272 return axisService;
273 }
274
275 /**
276 * Get the AxisConfiguration
277 *
278 * @return the AxisConfiguration associated with the client.
279 */
280 public AxisConfiguration getAxisConfiguration() {
281 synchronized (this.axisConfig) {
282 return axisConfig;
283 }
284 }
285
286 /**
287 * Return the AxisService this is a client for. This is primarily useful when the AxisService is
288 * created anonymously or from WSDL as otherwise the user had the AxisService to start with.
289 *
290 * @return the axisService
291 */
292 public AxisService getAxisService() {
293 return axisService;
294 }
295
296 /**
297 * Set the basic client configuration related to this service interaction.
298 *
299 * @param options (non-<code>null</code>)
300 */
301 public void setOptions(Options options) {
302 this.options = options;
303 }
304
305 /**
306 * Get the basic client configuration from this service interaction.
307 *
308 * @return options
309 */
310 public Options getOptions() {
311 return options;
312 }
313
314 /**
315 * Set a client configuration to override the normal options used by an operation client. Any
316 * values set in this configuration will be used for each client, with the standard values for
317 * the client still used for any values not set in the override configuration.
318 *
319 * @param overrideOptions the Options to use
320 */
321 public void setOverrideOptions(Options overrideOptions) {
322 this.overrideOptions = overrideOptions;
323 }
324
325 /**
326 * Get the client configuration used to override the normal options set by an operation client.
327 *
328 * @return override options
329 */
330 public Options getOverrideOptions() {
331 return overrideOptions;
332 }
333
334 /**
335 * Engage a module for this service client.
336 *
337 * @param moduleName name of the module to engage
338 * @throws AxisFault if something goes wrong
339 * @deprecated Please use String version instead
340 */
341 public void engageModule(QName moduleName) throws AxisFault {
342 engageModule(moduleName.getLocalPart());
343 }
344
345 /**
346 * Engage a module for this service client.
347 *
348 * @param moduleName name of the module to engage
349 * @throws AxisFault if something goes wrong
350 */
351 public void engageModule(String moduleName) throws AxisFault {
352 synchronized (this.axisConfig) {
353 AxisModule module = axisConfig.getModule(moduleName);
354 if (module != null) {
355 axisService.engageModule(module);
356 } else {
357 throw new AxisFault("Unable to engage module : " + moduleName);
358 }
359 }
360 }
361
362 /**
363 * Disengage a module for this service client
364 *
365 * @param moduleName name of Module to disengage
366 * @deprecated Please use String version instead
367 */
368 public void disengageModule(QName moduleName) {
369 disengageModule(moduleName.getLocalPart());
370 }
371
372 /**
373 * Disengage a module for this service client
374 *
375 * @param moduleName name of Module to disengage
376 */
377 public void disengageModule(String moduleName) {
378 synchronized (this.axisConfig) {
379 AxisModule module = axisConfig.getModule(moduleName);
380 if (module != null) {
381 try {
382 axisService.disengageModule(module);
383 } catch (AxisFault axisFault) {
384 log.error(axisFault.getMessage(), axisFault);
385 }
386 }
387 }
388 }
389
390 /**
391 * Add an arbitrary XML element as a header to be sent with outgoing messages.
392 *
393 * @param header header to be sent (non-<code>null</code>)
394 */
395 public void addHeader(OMElement header) {
396 if (headers == null) {
397 headers = new ArrayList<OMElement>();
398 }
399 headers.add(header);
400 }
401
402 /**
403 * Add SOAP Header to be sent with outgoing messages.
404 *
405 * @param header header to be sent (non-<code>null</code>)
406 */
407 public void addHeader(SOAPHeaderBlock header) {
408 if (headers == null) {
409 headers = new ArrayList<OMElement>();
410 }
411 headers.add(header);
412 }
413
414 /** Remove all headers for outgoing message. */
415 public void removeHeaders() {
416 if (headers != null) {
417 headers.clear();
418 }
419 }
420
421
422 /**
423 * Add a simple header containing some text to be sent with interactions.
424 *
425 * @param headerName name of header to add
426 * @param headerText text content for header
427 * @throws AxisFault in case of error
428 */
429 public void addStringHeader(QName headerName, String headerText) throws AxisFault {
430 if (headerName.getNamespaceURI() == null || "".equals(headerName.getNamespaceURI())) {
431 throw new AxisFault(
432 "Failed to add string header, you have to have namespaceURI for the QName");
433 }
434 OMElement omElement = OMAbstractFactory.getOMFactory().createOMElement(headerName, null);
435 omElement.setText(headerText);
436 addHeader(omElement);
437 }
438
439 /**
440 * Directly invoke an anonymous operation with a Robust In-Only MEP. This method just sends your
441 * supplied XML and possibly receives a fault. For more control, you can instead create a client
442 * for the operation and use that client to execute the send.
443 *
444 * @param elem XML to send
445 * @throws AxisFault if something goes wrong while sending, or if a fault is received in
446 * response (per the Robust In-Only MEP).
447 * @see #createClient(QName)
448 */
449 public void sendRobust(OMElement elem) throws AxisFault {
450 sendRobust(ANON_ROBUST_OUT_ONLY_OP, elem);
451 }
452
453 /**
454 * Directly invoke a named operation with a Robust In-Only MEP. This method just sends your
455 * supplied XML and possibly receives a fault. For more control, you can instead create a client
456 * for the operation and use that client to execute the send.
457 *
458 * @param operation name of operation to be invoked (non-<code>null</code>)
459 * @param elem XML to send
460 * @throws AxisFault if something goes wrong while sending it or if a fault is received in
461 * response (per the Robust In-Only MEP).
462 * @see #createClient(QName)
463 */
464 public void sendRobust(QName operation, OMElement elem) throws AxisFault {
465 MessageContext mc = new MessageContext();
466 fillSOAPEnvelope(mc, elem);
467 OperationClient mepClient = createClient(operation);
468 mepClient.addMessageContext(mc);
469 mepClient.execute(true);
470 }
471
472 /**
473 * Directly invoke an anonymous operation with an In-Only MEP. This method just sends your
474 * supplied XML without the possibility of any response from the service (even an error - though
475 * you can still get client-side errors such as "Host not found"). For more control, you can
476 * instead create a client for the operation and use that client to execute the send.
477 *
478 * @param elem XML to send
479 * @throws AxisFault ff something goes wrong trying to send the XML
480 * @see #createClient(QName)
481 */
482 public void fireAndForget(OMElement elem) throws AxisFault {
483 fireAndForget(ANON_OUT_ONLY_OP, elem);
484 }
485
486 /**
487 * Directly invoke a named operation with an In-Only MEP. This method just sends your supplied
488 * XML without the possibility of any response from the service (even an error - though you can
489 * still get client-side errors such as "Host not found"). For more control, you can instead
490 * create a client for the operation and use that client to execute the send.
491 *
492 * @param operation name of operation to be invoked (non-<code>null</code>)
493 * @param elem XML to send
494 * @throws AxisFault if something goes wrong trying to send the XML
495 * @see #createClient(QName)
496 */
497 public void fireAndForget(QName operation, OMElement elem) throws AxisFault {
498 // look up the appropriate axisop and create the client
499 OperationClient mepClient = createClient(operation);
500 // create a message context and put the payload in there along with any
501 // headers
502 MessageContext mc = new MessageContext();
503 fillSOAPEnvelope(mc, elem);
504 // add the message context there and have it go
505 mepClient.addMessageContext(mc);
506 mepClient.execute(false);
507 }
508
509 /**
510 * Directly invoke an anonymous operation with an In-Out MEP. This method sends your supplied
511 * XML and receives a response. For more control, you can instead create a client for the
512 * operation and use that client to execute the exchange.
513 *
514 * @param elem the data to send (becomes the content of SOAP body)
515 * @return response
516 * @throws AxisFault in case of error
517 * @see #createClient(QName)
518 */
519 public OMElement sendReceive(OMElement elem) throws AxisFault {
520 return sendReceive(ANON_OUT_IN_OP, elem);
521 }
522
523 /**
524 * Directly invoke a named operationQName with an In-Out MEP. This method sends your supplied
525 * XML and receives a response. For more control, you can instead create a client for the
526 * operationQName and use that client to execute the exchange.
527 *
528 * @param operationQName name of operationQName to be invoked (non-<code>null</code>)
529 * @param xmlPayload the data to send (becomes the content of SOAP body)
530 * @return response OMElement
531 * @throws AxisFault in case of error
532 */
533 public OMElement sendReceive(QName operationQName, OMElement xmlPayload)
534 throws AxisFault {
535 MessageContext messageContext = new MessageContext();
536 fillSOAPEnvelope(messageContext, xmlPayload);
537 OperationClient operationClient = createClient(operationQName);
538 operationClient.addMessageContext(messageContext);
539 operationClient.execute(true);
540 MessageContext response = operationClient
541 .getMessageContext(WSDLConstants.MESSAGE_LABEL_IN_VALUE);
542 if (options.isCallTransportCleanup()) {
543 response.getEnvelope().build();
544 cleanupTransport();
545 }
546 return response.getEnvelope().getBody().getFirstElement();
547 }
548
549 /**
550 * Directly invoke an anonymous operation with an In-Out MEP without waiting for a response.
551 * This method sends your supplied XML with response notification to your callback handler. For
552 * more control, you can instead create a client for the operation and use that client to
553 * execute the exchange.
554 *
555 * @param elem the data to send (becomes the content of SOAP body)
556 * @param callback a Callback which will be notified upon completion
557 * @throws AxisFault in case of error
558 * @see #createClient(QName)
559 * @deprecated Please use the AxisCallback interface rather than Callback, which has been
560 * deprecated
561 */
562 public void sendReceiveNonBlocking(OMElement elem, Callback callback)
563 throws AxisFault {
564 sendReceiveNonBlocking(ANON_OUT_IN_OP, elem, callback);
565 }
566
567 /**
568 * Directly invoke an anonymous operation with an In-Out MEP without waiting for a response.
569 * This method sends your supplied XML with response notification to your callback handler. For
570 * more control, you can instead create a client for the operation and use that client to
571 * execute the exchange.
572 *
573 * @param elem the data to send (becomes the content of SOAP body)
574 * @param callback a Callback which will be notified upon completion
575 * @throws AxisFault in case of error
576 * @see #createClient(QName)
577 */
578 public void sendReceiveNonBlocking(OMElement elem, AxisCallback callback)
579 throws AxisFault {
580 sendReceiveNonBlocking(ANON_OUT_IN_OP, elem, callback);
581 }
582
583 /**
584 * Directly invoke a named operation with an In-Out MEP without waiting for a response. This
585 * method sends your supplied XML with response notification to your callback handler. For more
586 * control, you can instead create a client for the operation and use that client to execute the
587 * exchange.
588 *
589 * @param operation name of operation to be invoked (non-<code>null</code>)
590 * @param elem the data to send (becomes the content of SOAP body)
591 * @param callback a Callback which will be notified upon completion
592 * @throws AxisFault in case of error
593 * @see #createClient(QName)
594 * @deprecated Please use the AxisCallback interface rather than Callback, which has been
595 * deprecated
596 */
597 public void sendReceiveNonBlocking(QName operation, OMElement elem, Callback callback)
598 throws AxisFault {
599 MessageContext mc = new MessageContext();
600 fillSOAPEnvelope(mc, elem);
601 OperationClient mepClient = createClient(operation);
602 // here a blocking invocation happens in a new thread, so the
603 // progamming model is non blocking
604 mepClient.setCallback(callback);
605 mepClient.addMessageContext(mc);
606 mepClient.execute(false);
607 }
608
609 /**
610 * Directly invoke a named operation with an In-Out MEP without waiting for a response. This
611 * method sends your supplied XML with response notification to your callback handler. For more
612 * control, you can instead create a client for the operation and use that client to execute the
613 * exchange.
614 *
615 * @param operation name of operation to be invoked (non-<code>null</code>)
616 * @param elem the data to send (becomes the content of SOAP body)
617 * @param callback a Callback which will be notified upon completion
618 * @throws AxisFault in case of error
619 * @see #createClient(QName)
620 */
621 public void sendReceiveNonBlocking(QName operation, OMElement elem, AxisCallback callback)
622 throws AxisFault {
623 MessageContext mc = new MessageContext();
624 fillSOAPEnvelope(mc, elem);
625 OperationClient mepClient = createClient(operation);
626 // here a blocking invocation happens in a new thread, so the
627 // progamming model is non blocking
628 mepClient.setCallback(callback);
629 mepClient.addMessageContext(mc);
630 mepClient.execute(false);
631 }
632
633 /**
634 * Create an operation client with the appropriate message exchange pattern (MEP). This method
635 * creates a full-function MEP client which can be used to exchange messages for a specific
636 * operation. It configures the constructed operation client to use the current normal and
637 * override options. This method is used internally, and also by generated client stub code.
638 *
639 * @param operationQName qualified name of operation (local name is operation name, namespace
640 * URI is just the empty string)
641 * @return client configured to talk to the given operation
642 * @throws AxisFault if the operation is not found
643 */
644 public OperationClient createClient(QName operationQName) throws AxisFault {
645 AxisOperation axisOperation = axisService.getOperation(operationQName);
646 if (axisOperation == null) {
647 throw new AxisFault(Messages
648 .getMessage("operationnotfound", operationQName.getLocalPart()));
649 }
650
651 // add the option properties to the service context
652 String key;
653 for (Object o : options.getProperties().keySet()) {
654 key = (String)o;
655 serviceContext.setProperty(key, options.getProperties().get(key));
656 }
657 OperationClient operationClient = axisOperation.createClient(serviceContext, options);
658
659 // if overide options have been set, that means we need to make sure
660 // those options override the options of even the operation client. So,
661 // what we do is switch the parents around to make that work.
662 if (overrideOptions != null) {
663 overrideOptions.setParent(operationClient.getOptions());
664 operationClient.setOptions(overrideOptions);
665 }
666 return operationClient;
667 }
668
669 /**
670 * Return the SOAP factory to use depending on what options have been set. If the SOAP version
671 * can not be seen in the options, version 1.1 is the default.
672 *
673 * @return the SOAP factory
674 * @see Options#setSoapVersionURI(String)
675 */
676 private SOAPFactory getSOAPFactory() {
677 String soapVersionURI = options.getSoapVersionURI();
678 if (SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI.equals(soapVersionURI)) {
679 return OMAbstractFactory.getSOAP12Factory();
680 } else {
681 // make the SOAP 1.1 the default SOAP version
682 return OMAbstractFactory.getSOAP11Factory();
683 }
684 }
685
686 /**
687 * Prepare a SOAP envelope with the stuff to be sent.
688 *
689 * @param messageContext the message context to be filled
690 * @param xmlPayload the payload content
691 * @throws AxisFault if something goes wrong
692 */
693 private void fillSOAPEnvelope(MessageContext messageContext, OMElement xmlPayload)
694 throws AxisFault {
695 messageContext.setServiceContext(serviceContext);
696 SOAPFactory soapFactory = getSOAPFactory();
697 SOAPEnvelope envelope = soapFactory.getDefaultEnvelope();
698 if (xmlPayload != null) {
699 envelope.getBody().addChild(xmlPayload);
700 }
701 addHeadersToEnvelope(envelope);
702 messageContext.setEnvelope(envelope);
703 }
704
705
706 /**
707 * Add all configured headers to a SOAP envelope.
708 *
709 * @param envelope the SOAPEnvelope in which to write the headers
710 */
711 public void addHeadersToEnvelope(SOAPEnvelope envelope) {
712 if (headers != null) {
713 SOAPHeader soapHeader = envelope.getHeader();
714 for (Object header : headers) {
715 soapHeader.addChild((OMElement)header);
716 }
717 }
718 }
719
720
721 /**
722 * Get the endpoint reference for this client using a particular transport.
723 *
724 * @param transport transport name (non-<code>null</code>)
725 * @return local endpoint
726 * @throws AxisFault in case of error
727 */
728 public EndpointReference getMyEPR(String transport) throws AxisFault {
729 return serviceContext.getMyEPR(transport);
730 }
731
732 /**
733 * Get the endpoint reference for the service.
734 *
735 * @return service endpoint
736 */
737 public EndpointReference getTargetEPR() {
738 return serviceContext.getTargetEPR();
739 }
740
741 /**
742 * Set the endpoint reference for the service.
743 *
744 * @param targetEpr the EPR this ServiceClient should target
745 */
746 public void setTargetEPR(EndpointReference targetEpr) {
747 serviceContext.setTargetEPR(targetEpr);
748 options.setTo(targetEpr);
749 }
750
751 /**
752 * Gets the last OperationContext
753 *
754 * @return the last OperationContext that was invoked by this ServiceClient
755 */
756 public OperationContext getLastOperationContext() {
757 return serviceContext.getLastOperationContext();
758 }
759
760 /**
761 * Sets whether or not to cache the last OperationContext
762 *
763 * @param cachingOpContext true if we should hold onto the last active OperationContext
764 * @deprecated
765 */
766 public void setCachingOperationContext(boolean cachingOpContext) {
767 serviceContext.setCachingOperationContext(cachingOpContext);
768 }
769
770
771 /**
772 * Get the service context.
773 *
774 * @return context
775 */
776 public ServiceContext getServiceContext() {
777 return serviceContext;
778 }
779
780 protected void finalize() throws Throwable {
781 super.finalize();
782 cleanup();
783 }
784
785 /**
786 * Clean up configuration created with this client. Call this method when you're done using the
787 * client, in order to discard any associated resources.
788 *
789 * @throws AxisFault in case of error
790 */
791 public void cleanup() throws AxisFault {
792 // if a configuration context was created for this client there'll also
793 // be a service group, so discard that
794 if (!createConfigCtx) {
795 String serviceGroupName = axisService.getAxisServiceGroup().getServiceGroupName();
796 AxisConfiguration axisConfiguration = configContext.getAxisConfiguration();
797 AxisServiceGroup asg = axisConfiguration.getServiceGroup(serviceGroupName);
798 if ((asg != null) && removeAxisService) {
799 axisConfiguration.removeServiceGroup(serviceGroupName);
800 }
801 } else {
802 configContext.terminate();
803 }
804 }
805
806 public void cleanupTransport() throws AxisFault {
807 if (getLastOperationContext() != null) {
808 MessageContext outMessageContext =
809 getLastOperationContext()
810 .getMessageContext(WSDLConstants.MESSAGE_LABEL_OUT_VALUE);
811 if (outMessageContext != null) {
812 outMessageContext.getTransportOut().getSender().cleanup(outMessageContext);
813 }
814 }
815 }
816
817 /**
818 * Configure the ServiceClient to interact with the Web service described by the specified
819 * AxisService object.
820 *
821 * @param axisService the AxisService that represents the new Web service.
822 * @throws AxisFault if an error occurs while configuring the ServiceClient.
823 */
824 public void setAxisService(AxisService axisService) throws AxisFault {
825
826 if (axisService == null) {
827 // AxisFault?
828 throw new IllegalArgumentException("AxisService is null");
829 }
830
831 synchronized (this.axisConfig) {
832 axisConfig.removeService(this.axisService.getName());
833 this.axisService = axisService;
834
835 axisService.setClientSide(true);
836 axisConfig.addService(axisService);
837 }
838 AxisServiceGroup axisServiceGroup = axisService.getAxisServiceGroup();
839 ServiceGroupContext serviceGroupContext =
840 configContext.createServiceGroupContext(axisServiceGroup);
841 this.serviceContext = serviceGroupContext.getServiceContext(axisService);
842 }
843
844 /** @see java.lang.Object#hashCode() */
845 public int hashCode() {
846 return this.hashCode;
847 }
848
849 /** @see java.lang.Object#equals(java.lang.Object) */
850 public boolean equals(Object obj) {
851 if (this == obj)
852 return true;
853 if (obj == null)
854 return false;
855 if (!(obj instanceof ServiceClient))
856 return false;
857 final ServiceClient other = (ServiceClient)obj;
858 return hashCode == other.hashCode;
859 }
860
861 }