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 {@code defaultEndPointAddress}.
 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 {@code defaultEndPointAddress}.
 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 {@code defaultEndPointAddress}.
 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 {@code defaultEndPointAddress}.
 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 }