View Javadoc
1   /*
2    * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package com.sun.xml.internal.ws.client;
27  
28  import com.sun.istack.internal.NotNull;
29  import com.sun.istack.internal.Nullable;
30  import com.sun.xml.internal.stream.buffer.XMLStreamBuffer;
31  import com.sun.xml.internal.ws.addressing.WSEPRExtension;
32  import com.sun.xml.internal.ws.api.BindingID;
33  import com.sun.xml.internal.ws.api.Component;
34  import com.sun.xml.internal.ws.api.ComponentFeature;
35  import com.sun.xml.internal.ws.api.ComponentFeature.Target;
36  import com.sun.xml.internal.ws.api.ComponentRegistry;
37  import com.sun.xml.internal.ws.api.ComponentsFeature;
38  import com.sun.xml.internal.ws.api.EndpointAddress;
39  import com.sun.xml.internal.ws.api.WSBinding;
40  import com.sun.xml.internal.ws.api.WSService;
41  import com.sun.xml.internal.ws.api.addressing.AddressingVersion;
42  import com.sun.xml.internal.ws.api.addressing.WSEndpointReference;
43  import com.sun.xml.internal.ws.api.client.WSPortInfo;
44  import com.sun.xml.internal.ws.api.message.AddressingUtils;
45  import com.sun.xml.internal.ws.api.message.Header;
46  import com.sun.xml.internal.ws.api.message.HeaderList;
47  import com.sun.xml.internal.ws.api.message.MessageHeaders;
48  import com.sun.xml.internal.ws.api.message.Packet;
49  import com.sun.xml.internal.ws.api.model.SEIModel;
50  import com.sun.xml.internal.ws.api.model.wsdl.WSDLPort;
51  import com.sun.xml.internal.ws.api.pipe.ClientTubeAssemblerContext;
52  import com.sun.xml.internal.ws.api.pipe.Engine;
53  import com.sun.xml.internal.ws.api.pipe.Fiber;
54  import com.sun.xml.internal.ws.api.pipe.FiberContextSwitchInterceptorFactory;
55  import com.sun.xml.internal.ws.api.pipe.SyncStartForAsyncFeature;
56  import com.sun.xml.internal.ws.api.pipe.Tube;
57  import com.sun.xml.internal.ws.api.pipe.TubelineAssembler;
58  import com.sun.xml.internal.ws.api.pipe.TubelineAssemblerFactory;
59  import com.sun.xml.internal.ws.api.server.Container;
60  import com.sun.xml.internal.ws.api.server.ContainerResolver;
61  import com.sun.xml.internal.ws.binding.BindingImpl;
62  import com.sun.xml.internal.ws.developer.JAXWSProperties;
63  import com.sun.xml.internal.ws.developer.WSBindingProvider;
64  import com.sun.xml.internal.ws.model.wsdl.WSDLDirectProperties;
65  import com.sun.xml.internal.ws.model.wsdl.WSDLPortProperties;
66  import com.sun.xml.internal.ws.model.wsdl.WSDLProperties;
67  import com.sun.xml.internal.ws.resources.ClientMessages;
68  import com.sun.xml.internal.ws.util.Pool;
69  import com.sun.xml.internal.ws.util.Pool.TubePool;
70  import com.sun.xml.internal.ws.util.RuntimeVersion;
71  import com.sun.xml.internal.ws.wsdl.OperationDispatcher;
72  import com.sun.org.glassfish.gmbal.ManagedObjectManager;
73  
74  import javax.xml.namespace.QName;
75  import javax.xml.stream.XMLStreamException;
76  import javax.xml.ws.BindingProvider;
77  import javax.xml.ws.EndpointReference;
78  import javax.xml.ws.RespectBindingFeature;
79  import javax.xml.ws.Response;
80  import javax.xml.ws.WebServiceException;
81  import javax.xml.ws.http.HTTPBinding;
82  import javax.xml.ws.wsaddressing.W3CEndpointReference;
83  import java.util.ArrayList;
84  import java.util.Collections;
85  import java.util.List;
86  import java.util.Map;
87  import java.util.Set;
88  import java.util.concurrent.CopyOnWriteArraySet;
89  import java.util.concurrent.Executor;
90  import java.util.logging.Level;
91  import java.util.logging.Logger;
92  import javax.management.ObjectName;
93  
94  /**
95   * Base class for stubs, which accept method invocations from
96   * client applications and pass the message to a {@link Tube}
97   * for processing.
98   *
99   * <p>
100  * This class implements the management of pipe instances,
101  * and most of the {@link BindingProvider} methods.
102  *
103  * @author Kohsuke Kawaguchi
104  */
105 public abstract class Stub implements WSBindingProvider, ResponseContextReceiver, ComponentRegistry  {
106     /**
107      * Internal flag indicating async dispatch should be used even when the
108      * SyncStartForAsyncInvokeFeature is present on the binding associated
109      * with a stub. There is no type associated with this property on the
110      * request context. Its presence is what triggers the 'prevent' behavior.
111      */
112     public static final String PREVENT_SYNC_START_FOR_ASYNC_INVOKE = "com.sun.xml.internal.ws.client.StubRequestSyncStartForAsyncInvoke";
113 
114     /**
115      * Reuse pipelines as it's expensive to create.
116      * <p>
117      * Set to null when {@link #close() closed}.
118      */
119     private Pool<Tube> tubes;
120 
121     private final Engine engine;
122 
123     /**
124      * The {@link WSServiceDelegate} object that owns us.
125      */
126     protected final WSServiceDelegate owner;
127 
128     /**
129      * Non-null if this stub is configured to talk to an EPR.
130      * <p>
131      * When this field is non-null, its reference parameters are sent as out-bound headers.
132      * This field can be null even when addressing is enabled, but if the addressing is
133      * not enabled, this field must be null.
134      * <p>
135      * Unlike endpoint address, we are not letting users to change the EPR,
136      * as it contains references to services and so on that we don't want to change.
137      */
138     protected
139     @Nullable
140     WSEndpointReference endpointReference;
141 
142     protected final BindingImpl binding;
143 
144     protected final WSPortInfo portInfo;
145 
146     /**
147      * represents AddressingVersion on binding if enabled, otherwise null;
148      */
149     protected AddressingVersion addrVersion;
150 
151     public RequestContext requestContext = new RequestContext();
152 
153     private final RequestContext cleanRequestContext;
154 
155     /**
156      * {@link ResponseContext} from the last synchronous operation.
157      */
158     private ResponseContext responseContext;
159     @Nullable
160     protected final WSDLPort wsdlPort;
161 
162     protected QName portname;
163 
164     /**
165      * {@link Header}s to be added to outbound {@link Packet}.
166      * The contents is determined by the user.
167      */
168     @Nullable
169     private volatile Header[] userOutboundHeaders;
170 
171     private final
172     @NotNull
173     WSDLProperties wsdlProperties;
174     protected OperationDispatcher operationDispatcher = null;
175     private final
176     @NotNull
177     ManagedObjectManager managedObjectManager;
178     private boolean managedObjectManagerClosed = false;
179 
180     private final Set<Component> components = new CopyOnWriteArraySet<Component>();
181 
182     /**
183      * @param master                 The created stub will send messages to this pipe.
184      * @param binding                As a {@link BindingProvider}, this object will
185      *                               return this binding from {@link BindingProvider#getBinding()}.
186      * @param defaultEndPointAddress The destination of the message. The actual destination
187      *                               could be overridden by {@link RequestContext}.
188      * @param epr                    To create a stub that sends out reference parameters
189      *                               of a specific EPR, give that instance. Otherwise null.
190      *                               Its address field will not be used, and that should be given
191      *                               separately as the <tt>defaultEndPointAddress</tt>.
192      */
193     @Deprecated
194     protected Stub(WSServiceDelegate owner, Tube master, BindingImpl binding, WSDLPort wsdlPort, EndpointAddress defaultEndPointAddress, @Nullable WSEndpointReference epr) {
195         this(owner, master, null, null, binding, wsdlPort, defaultEndPointAddress, epr);
196     }
197 
198     /**
199      * @param portname               The name of this port
200      * @param master                 The created stub will send messages to this pipe.
201      * @param binding                As a {@link BindingProvider}, this object will
202      *                               return this binding from {@link BindingProvider#getBinding()}.
203      * @param defaultEndPointAddress The destination of the message. The actual destination
204      *                               could be overridden by {@link RequestContext}.
205      * @param epr                    To create a stub that sends out reference parameters
206      *                               of a specific EPR, give that instance. Otherwise null.
207      *                               Its address field will not be used, and that should be given
208      *                               separately as the <tt>defaultEndPointAddress</tt>.
209      */
210     @Deprecated
211     protected Stub(QName portname, WSServiceDelegate owner, Tube master, BindingImpl binding, WSDLPort wsdlPort, EndpointAddress defaultEndPointAddress, @Nullable WSEndpointReference epr) {
212         this(owner, master, null, portname, binding, wsdlPort, defaultEndPointAddress, epr);
213     }
214 
215     /**
216      * @param portInfo               PortInfo  for this stub
217      * @param binding                As a {@link BindingProvider}, this object will
218      *                               return this binding from {@link BindingProvider#getBinding()}.
219      * @param master                 The created stub will send messages to this pipe.
220      * @param defaultEndPointAddress The destination of the message. The actual destination
221      *                               could be overridden by {@link RequestContext}.
222      * @param epr                    To create a stub that sends out reference parameters
223      *                               of a specific EPR, give that instance. Otherwise null.
224      *                               Its address field will not be used, and that should be given
225      *                               separately as the <tt>defaultEndPointAddress</tt>.
226      */
227     protected Stub(WSPortInfo portInfo, BindingImpl binding, Tube master,EndpointAddress defaultEndPointAddress, @Nullable WSEndpointReference epr) {
228          this((WSServiceDelegate) portInfo.getOwner(), master, portInfo, null, binding,portInfo.getPort(), defaultEndPointAddress, epr);
229     }
230 
231   /**
232    * @param portInfo               PortInfo  for this stub
233    * @param binding                As a {@link BindingProvider}, this object will
234    *                               return this binding from {@link BindingProvider#getBinding()}.
235    * @param defaultEndPointAddress The destination of the message. The actual destination
236    *                               could be overridden by {@link RequestContext}.
237    * @param epr                    To create a stub that sends out reference parameters
238    *                               of a specific EPR, give that instance. Otherwise null.
239    *                               Its address field will not be used, and that should be given
240    *                               separately as the <tt>defaultEndPointAddress</tt>.
241    */
242   protected Stub(WSPortInfo portInfo, BindingImpl binding, EndpointAddress defaultEndPointAddress, @Nullable WSEndpointReference epr) {
243        this(portInfo,binding,null, defaultEndPointAddress,epr);
244 
245   }
246 
247     private Stub(WSServiceDelegate owner, @Nullable Tube master, @Nullable WSPortInfo portInfo, QName portname, BindingImpl binding, @Nullable WSDLPort wsdlPort, EndpointAddress defaultEndPointAddress, @Nullable WSEndpointReference epr) {
248         Container old = ContainerResolver.getDefault().enterContainer(owner.getContainer());
249         try {
250             this.owner = owner;
251             this.portInfo = portInfo;
252             this.wsdlPort = wsdlPort != null ? wsdlPort : (portInfo != null ? portInfo.getPort() : null);
253             this.portname = portname;
254             if (portname == null) {
255                 if (portInfo != null) {
256                     this.portname = portInfo.getPortName();
257                 } else if (wsdlPort != null) {
258                     this.portname = wsdlPort.getName();
259                 }
260             }
261             this.binding = binding;
262 
263             ComponentFeature cf = binding.getFeature(ComponentFeature.class);
264             if (cf != null && Target.STUB.equals(cf.getTarget())) {
265                 components.add(cf.getComponent());
266             }
267             ComponentsFeature csf = binding.getFeature(ComponentsFeature.class);
268             if (csf != null) {
269                 for (ComponentFeature cfi : csf.getComponentFeatures()) {
270                     if (Target.STUB.equals(cfi.getTarget()))
271                         components.add(cfi.getComponent());
272                 }
273             }
274 
275             // if there is an EPR, EPR's address should be used for invocation instead of default address
276             if (epr != null) {
277                 this.requestContext.setEndPointAddressString(epr.getAddress());
278             } else {
279                 this.requestContext.setEndpointAddress(defaultEndPointAddress);
280             }
281             this.engine = new Engine(getStringId(), owner.getContainer(), owner.getExecutor());
282             this.endpointReference = epr;
283             wsdlProperties = (wsdlPort == null) ? new WSDLDirectProperties(owner.getServiceName(), portname) : new WSDLPortProperties(wsdlPort);
284 
285             this.cleanRequestContext = this.requestContext.copy();
286 
287             // ManagedObjectManager MUST be created before the pipeline
288             // is constructed.
289 
290             managedObjectManager = new MonitorRootClient(this).createManagedObjectManager(this);
291 
292             if (master != null) {
293                 this.tubes = new TubePool(master);
294             } else {
295                 this.tubes = new TubePool(createPipeline(portInfo, binding));
296             }
297 
298             addrVersion = binding.getAddressingVersion();
299 
300             // This needs to happen after createPipeline.
301             // TBD: Check if it needs to happen outside the Stub constructor.
302             managedObjectManager.resumeJMXRegistration();
303         } finally {
304             ContainerResolver.getDefault().exitContainer(old);
305         }
306     }
307 
308     /**
309      * Creates a new pipeline for the given port name.
310      */
311     private Tube createPipeline(WSPortInfo portInfo, WSBinding binding) {
312         //Check all required WSDL extensions are understood
313         checkAllWSDLExtensionsUnderstood(portInfo, binding);
314         SEIModel seiModel = null;
315         Class sei = null;
316         if (portInfo instanceof SEIPortInfo) {
317                 SEIPortInfo sp = (SEIPortInfo) portInfo;
318             seiModel = sp.model;
319             sei = sp.sei;
320         }
321         BindingID bindingId = portInfo.getBindingId();
322 
323         TubelineAssembler assembler = TubelineAssemblerFactory.create(
324                 Thread.currentThread().getContextClassLoader(), bindingId, owner.getContainer());
325         if (assembler == null) {
326             throw new WebServiceException("Unable to process bindingID=" + bindingId); // TODO: i18n
327         }
328         return assembler.createClient(
329                 new ClientTubeAssemblerContext(
330                         portInfo.getEndpointAddress(),
331                         portInfo.getPort(),
332                         this, binding, owner.getContainer(), ((BindingImpl) binding).createCodec(), seiModel, sei));
333     }
334 
335     public WSDLPort getWSDLPort() {
336         return wsdlPort;
337     }
338 
339     public WSService getService() {
340         return owner;
341     }
342 
343     public Pool<Tube> getTubes() {
344         return tubes;
345     }
346 
347     /**
348      * Checks only if RespectBindingFeature is enabled
349      * checks if all required wsdl extensions in the
350      * corresponding wsdl:Port are understood when RespectBindingFeature is enabled.
351      * @throws WebServiceException
352      *      when any wsdl extension that has wsdl:required=true is not understood
353      */
354     private static void checkAllWSDLExtensionsUnderstood(WSPortInfo port, WSBinding binding) {
355         if (port.getPort() != null && binding.isFeatureEnabled(RespectBindingFeature.class)) {
356             port.getPort().areRequiredExtensionsUnderstood();
357         }
358     }
359 
360     @Override
361     public WSPortInfo getPortInfo() {
362         return portInfo;
363     }
364 
365     /**
366      * Nullable when there is no associated WSDL Model
367      * @return
368      */
369     public
370     @Nullable
371     OperationDispatcher getOperationDispatcher() {
372         if (operationDispatcher == null && wsdlPort != null) {
373             operationDispatcher = new OperationDispatcher(wsdlPort, binding, null);
374         }
375         return operationDispatcher;
376     }
377 
378     /**
379      * Gets the port name that this stub is configured to talk to.
380      * <p>
381      * When {@link #wsdlPort} is non-null, the port name is always
382      * the same as {@link WSDLPort#getName()}, but this method
383      * returns a port name even if no WSDL is available for this stub.
384      */
385     protected abstract
386     @NotNull
387     QName getPortName();
388 
389     /**
390      * Gets the service name that this stub is configured to talk to.
391      * <p>
392      * When {@link #wsdlPort} is non-null, the service name is always
393      * the same as the one that's inferred from {@link WSDLPort#getOwner()},
394      * but this method returns a port name even if no WSDL is available for
395      * this stub.
396      */
397     protected final
398     @NotNull
399     QName getServiceName() {
400         return owner.getServiceName();
401     }
402 
403     /**
404      * Gets the {@link Executor} to be used for asynchronous method invocations.
405      * <p>
406      * Note that the value this method returns may different from invocations
407      * to invocations. The caller must not cache.
408      *
409      * @return always non-null.
410      */
411     public final Executor getExecutor() {
412         return owner.getExecutor();
413     }
414 
415     /**
416      * Passes a message to a pipe for processing.
417      * <p>
418      * Unlike {@link Tube} instances,
419      * this method is thread-safe and can be invoked from
420      * multiple threads concurrently.
421      *
422      * @param packet         The message to be sent to the server
423      * @param requestContext The {@link RequestContext} when this invocation is originally scheduled.
424      *                       This must be the same object as {@link #requestContext} for synchronous
425      *                       invocations, but for asynchronous invocations, it needs to be a snapshot
426      *                       captured at the point of invocation, to correctly satisfy the spec requirement.
427      * @param receiver       Receives the {@link ResponseContext}. Since the spec requires
428      *                       that the asynchronous invocations must not update response context,
429      *                       depending on the mode of invocation they have to go to different places.
430      *                       So we take a setter that abstracts that away.
431      */
432     protected final Packet process(Packet packet, RequestContext requestContext, ResponseContextReceiver receiver) {
433         packet.isSynchronousMEP = true;
434         packet.component = this;
435         configureRequestPacket(packet, requestContext);
436         Pool<Tube> pool = tubes;
437         if (pool == null) {
438             throw new WebServiceException("close method has already been invoked"); // TODO: i18n
439         }
440 
441         Fiber fiber = engine.createFiber();
442         configureFiber(fiber);
443 
444         // then send it away!
445         Tube tube = pool.take();
446 
447         try {
448             return fiber.runSync(tube, packet);
449         } finally {
450             // this allows us to capture the packet even when the call failed with an exception.
451             // when the call fails with an exception it's no longer a 'reply' but it may provide some information
452             // about what went wrong.
453 
454             // note that Packet can still be updated after
455             // ResponseContext is created.
456             Packet reply = (fiber.getPacket() == null) ? packet : fiber.getPacket();
457             receiver.setResponseContext(new ResponseContext(reply));
458 
459             pool.recycle(tube);
460         }
461     }
462 
463     private void configureRequestPacket(Packet packet, RequestContext requestContext) {
464         // fill in Packet
465         packet.proxy = this;
466         packet.handlerConfig = binding.getHandlerConfig();
467 
468         // to make it multi-thread safe we need to first get a stable snapshot
469         Header[] hl = userOutboundHeaders;
470         if (hl != null) {
471             MessageHeaders mh = packet.getMessage().getHeaders();
472             for (Header h : hl) {
473                 mh.add(h);
474             }
475         }
476 
477         requestContext.fill(packet, (binding.getAddressingVersion() != null));
478         packet.addSatellite(wsdlProperties);
479 
480         if (addrVersion != null) {
481             // populate request WS-Addressing headers
482             MessageHeaders headerList = packet.getMessage().getHeaders();
483             AddressingUtils.fillRequestAddressingHeaders(headerList, wsdlPort, binding, packet);
484 
485 
486             // Spec is not clear on if ReferenceParameters are to be added when addressing is not enabled,
487             // but the EPR has ReferenceParameters.
488             // Current approach: Add ReferenceParameters only if addressing enabled.
489             if (endpointReference != null) {
490                 endpointReference.addReferenceParametersToList(packet.getMessage().getHeaders());
491             }
492         }
493     }
494 
495     /**
496      * Passes a message through a {@link Tube}line for processing. The processing happens
497      * asynchronously and when the response is available, Fiber.CompletionCallback is
498      * called. The processing could happen on multiple threads.
499      *
500      * <p>
501      * Unlike {@link Tube} instances,
502      * this method is thread-safe and can be invoked from
503      * multiple threads concurrently.
504      *
505      * @param receiver       The {@link Response} implementation
506      * @param request         The message to be sent to the server
507      * @param requestContext The {@link RequestContext} when this invocation is originally scheduled.
508      *                       This must be the same object as {@link #requestContext} for synchronous
509      *                       invocations, but for asynchronous invocations, it needs to be a snapshot
510      *                       captured at the point of invocation, to correctly satisfy the spec requirement.
511      * @param completionCallback Once the processing is done, the callback is invoked.
512      */
513     protected final void processAsync(AsyncResponseImpl<?> receiver, Packet request, RequestContext requestContext, final Fiber.CompletionCallback completionCallback) {
514         // fill in Packet
515         request.component = this;
516         configureRequestPacket(request, requestContext);
517 
518         final Pool<Tube> pool = tubes;
519         if (pool == null) {
520             throw new WebServiceException("close method has already been invoked"); // TODO: i18n
521         }
522 
523         final Fiber fiber = engine.createFiber();
524         configureFiber(fiber);
525 
526         receiver.setCancelable(fiber);
527 
528         // check race condition on cancel
529         if (receiver.isCancelled()) {
530             return;
531         }
532 
533         FiberContextSwitchInterceptorFactory fcsif = owner.getSPI(FiberContextSwitchInterceptorFactory.class);
534         if (fcsif != null) {
535             fiber.addInterceptor(fcsif.create());
536         }
537 
538         // then send it away!
539         final Tube tube = pool.take();
540 
541         Fiber.CompletionCallback fiberCallback = new Fiber.CompletionCallback() {
542             @Override
543             public void onCompletion(@NotNull Packet response) {
544                 pool.recycle(tube);
545                 completionCallback.onCompletion(response);
546             }
547 
548             @Override
549             public void onCompletion(@NotNull Throwable error) {
550                 // let's not reuse tubes as they might be in a wrong state, so not
551                 // calling pool.recycle()
552                 completionCallback.onCompletion(error);
553             }
554         };
555 
556         // Check for SyncStartForAsyncInvokeFeature
557 
558         fiber.start(tube, request, fiberCallback,
559                         getBinding().isFeatureEnabled(SyncStartForAsyncFeature.class) &&
560                         !requestContext.containsKey(PREVENT_SYNC_START_FOR_ASYNC_INVOKE));
561     }
562 
563     protected void configureFiber(Fiber fiber) {
564         // no-op in the base class, but can be used by derived classes to configure the Fiber prior
565         // to invocation
566     }
567 
568     private static final Logger monitoringLogger = Logger.getLogger(com.sun.xml.internal.ws.util.Constants.LoggingDomain + ".monitoring");
569 
570     @Override
571     public void close() {
572         TubePool tp = (TubePool) tubes;
573         if (tp != null) {
574             // multi-thread safety of 'close' needs to be considered more carefully.
575             // some calls might be pending while this method is invoked. Should we
576             // block until they are complete, or should we abort them (but how?)
577             Tube p = tp.takeMaster();
578             p.preDestroy();
579             tubes = null;
580         }
581         if (!managedObjectManagerClosed) {
582             try {
583                 final ObjectName name = managedObjectManager.getObjectName(managedObjectManager.getRoot());
584                 // The name is null when the MOM is a NOOP.
585                 if (name != null) {
586                     monitoringLogger.log(Level.INFO, "Closing Metro monitoring root: {0}", name);
587                 }
588                 managedObjectManager.close();
589             } catch (java.io.IOException e) {
590                 monitoringLogger.log(Level.WARNING, "Ignoring error when closing Managed Object Manager", e);
591             }
592             managedObjectManagerClosed = true;
593         }
594     }
595 
596     @Override
597     public final WSBinding getBinding() {
598         return binding;
599     }
600 
601     @Override
602     public final Map<String, Object> getRequestContext() {
603         return requestContext.asMap();
604     }
605 
606     public void resetRequestContext() {
607         requestContext = cleanRequestContext.copy();
608     }
609 
610     @Override
611     public final ResponseContext getResponseContext() {
612         return responseContext;
613     }
614 
615     @Override
616     public void setResponseContext(ResponseContext rc) {
617         this.responseContext = rc;
618     }
619 
620     private String getStringId() {
621         return RuntimeVersion.VERSION + ": Stub for " + getRequestContext().get(BindingProvider.ENDPOINT_ADDRESS_PROPERTY);
622     }
623 
624     @Override
625     public String toString() {
626         return getStringId();
627     }
628 
629     @Override
630     public final WSEndpointReference getWSEndpointReference() {
631         if (binding.getBindingID().equals(HTTPBinding.HTTP_BINDING)) {
632             throw new java.lang.UnsupportedOperationException(
633                         ClientMessages.UNSUPPORTED_OPERATION("BindingProvider.getEndpointReference(Class<T> class)", "XML/HTTP Binding", "SOAP11 or SOAP12 Binding")
634                     );
635         }
636 
637         if (endpointReference != null) {
638             return endpointReference;
639         }
640 
641         String eprAddress = requestContext.getEndpointAddress().toString();
642         QName portTypeName = null;
643         String wsdlAddress = null;
644         List<WSEndpointReference.EPRExtension> wsdlEPRExtensions = new ArrayList<WSEndpointReference.EPRExtension>();
645         if (wsdlPort != null) {
646             portTypeName = wsdlPort.getBinding().getPortTypeName();
647             wsdlAddress = eprAddress + "?wsdl";
648 
649             //gather EPRExtensions specified in WSDL.
650             try {
651                 WSEndpointReference wsdlEpr = wsdlPort.getEPR();
652                 if (wsdlEpr != null) {
653                     for (WSEndpointReference.EPRExtension extnEl : wsdlEpr.getEPRExtensions()) {
654                         wsdlEPRExtensions.add(new WSEPRExtension(
655                                 XMLStreamBuffer.createNewBufferFromXMLStreamReader(extnEl.readAsXMLStreamReader()), extnEl.getQName()));
656                     }
657                 }
658 
659             } catch (XMLStreamException ex) {
660                 throw new WebServiceException(ex);
661             }
662         }
663         AddressingVersion av = AddressingVersion.W3C;
664         this.endpointReference = new WSEndpointReference(
665                 av, eprAddress, getServiceName(), getPortName(), portTypeName, null, wsdlAddress, null, wsdlEPRExtensions, null);
666 
667         return this.endpointReference;
668     }
669 
670 
671     @Override
672     public final W3CEndpointReference getEndpointReference() {
673         if (binding.getBindingID().equals(HTTPBinding.HTTP_BINDING)) {
674             throw new java.lang.UnsupportedOperationException(
675                         ClientMessages.UNSUPPORTED_OPERATION("BindingProvider.getEndpointReference()", "XML/HTTP Binding", "SOAP11 or SOAP12 Binding"));
676         }
677         return getEndpointReference(W3CEndpointReference.class);
678     }
679 
680     @Override
681     public final <T extends EndpointReference> T getEndpointReference(Class<T> clazz) {
682         return getWSEndpointReference().toSpec(clazz);
683     }
684 
685     public
686     @NotNull
687     @Override
688     ManagedObjectManager getManagedObjectManager() {
689         return managedObjectManager;
690     }
691 
692     //
693 //
694 // WSBindingProvider methods
695 //
696 //
697     @Override
698     public final void setOutboundHeaders(List<Header> headers) {
699         if (headers == null) {
700             this.userOutboundHeaders = null;
701         } else {
702             for (Header h : headers) {
703                 if (h == null) {
704                     throw new IllegalArgumentException();
705                 }
706             }
707             userOutboundHeaders = headers.toArray(new Header[headers.size()]);
708         }
709     }
710 
711     @Override
712     public final void setOutboundHeaders(Header... headers) {
713         if (headers == null) {
714             this.userOutboundHeaders = null;
715         } else {
716             for (Header h : headers) {
717                 if (h == null) {
718                     throw new IllegalArgumentException();
719                 }
720             }
721             Header[] hl = new Header[headers.length];
722             System.arraycopy(headers, 0, hl, 0, headers.length);
723             userOutboundHeaders = hl;
724         }
725     }
726 
727     @Override
728     public final List<Header> getInboundHeaders() {
729         return Collections.unmodifiableList(((MessageHeaders)
730                 responseContext.get(JAXWSProperties.INBOUND_HEADER_LIST_PROPERTY)).asList());
731     }
732 
733     @Override
734     public final void setAddress(String address) {
735         requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, address);
736     }
737 
738     @Override
739     public <S> S getSPI(Class<S> spiType) {
740         for (Component c : components) {
741             S s = c.getSPI(spiType);
742             if (s != null) {
743                 return s;
744             }
745         }
746         return owner.getSPI(spiType);
747     }
748 
749     @Override
750     public Set<Component> getComponents() {
751         return components;
752     }
753 }