aoqi@0: /* aoqi@0: * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. Oracle designates this aoqi@0: * particular file as subject to the "Classpath" exception as provided aoqi@0: * by Oracle in the LICENSE file that accompanied this code. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: */ aoqi@0: aoqi@0: package com.sun.xml.internal.ws.client; aoqi@0: aoqi@0: import com.sun.istack.internal.NotNull; aoqi@0: import com.sun.istack.internal.Nullable; aoqi@0: import com.sun.xml.internal.stream.buffer.XMLStreamBuffer; aoqi@0: import com.sun.xml.internal.ws.addressing.WSEPRExtension; aoqi@0: import com.sun.xml.internal.ws.api.BindingID; aoqi@0: import com.sun.xml.internal.ws.api.Component; aoqi@0: import com.sun.xml.internal.ws.api.ComponentFeature; aoqi@0: import com.sun.xml.internal.ws.api.ComponentFeature.Target; aoqi@0: import com.sun.xml.internal.ws.api.ComponentRegistry; aoqi@0: import com.sun.xml.internal.ws.api.ComponentsFeature; aoqi@0: import com.sun.xml.internal.ws.api.EndpointAddress; aoqi@0: import com.sun.xml.internal.ws.api.WSBinding; aoqi@0: import com.sun.xml.internal.ws.api.WSService; aoqi@0: import com.sun.xml.internal.ws.api.addressing.AddressingVersion; aoqi@0: import com.sun.xml.internal.ws.api.addressing.WSEndpointReference; aoqi@0: import com.sun.xml.internal.ws.api.client.WSPortInfo; aoqi@0: import com.sun.xml.internal.ws.api.message.AddressingUtils; aoqi@0: import com.sun.xml.internal.ws.api.message.Header; aoqi@0: import com.sun.xml.internal.ws.api.message.HeaderList; aoqi@0: import com.sun.xml.internal.ws.api.message.MessageHeaders; aoqi@0: import com.sun.xml.internal.ws.api.message.Packet; aoqi@0: import com.sun.xml.internal.ws.api.model.SEIModel; aoqi@0: import com.sun.xml.internal.ws.api.model.wsdl.WSDLPort; aoqi@0: import com.sun.xml.internal.ws.api.pipe.ClientTubeAssemblerContext; aoqi@0: import com.sun.xml.internal.ws.api.pipe.Engine; aoqi@0: import com.sun.xml.internal.ws.api.pipe.Fiber; aoqi@0: import com.sun.xml.internal.ws.api.pipe.FiberContextSwitchInterceptorFactory; aoqi@0: import com.sun.xml.internal.ws.api.pipe.SyncStartForAsyncFeature; aoqi@0: import com.sun.xml.internal.ws.api.pipe.Tube; aoqi@0: import com.sun.xml.internal.ws.api.pipe.TubelineAssembler; aoqi@0: import com.sun.xml.internal.ws.api.pipe.TubelineAssemblerFactory; aoqi@0: import com.sun.xml.internal.ws.api.server.Container; aoqi@0: import com.sun.xml.internal.ws.api.server.ContainerResolver; aoqi@0: import com.sun.xml.internal.ws.binding.BindingImpl; aoqi@0: import com.sun.xml.internal.ws.developer.JAXWSProperties; aoqi@0: import com.sun.xml.internal.ws.developer.WSBindingProvider; aoqi@0: import com.sun.xml.internal.ws.model.wsdl.WSDLDirectProperties; aoqi@0: import com.sun.xml.internal.ws.model.wsdl.WSDLPortProperties; aoqi@0: import com.sun.xml.internal.ws.model.wsdl.WSDLProperties; aoqi@0: import com.sun.xml.internal.ws.resources.ClientMessages; aoqi@0: import com.sun.xml.internal.ws.util.Pool; aoqi@0: import com.sun.xml.internal.ws.util.Pool.TubePool; aoqi@0: import com.sun.xml.internal.ws.util.RuntimeVersion; aoqi@0: import com.sun.xml.internal.ws.wsdl.OperationDispatcher; aoqi@0: import com.sun.org.glassfish.gmbal.ManagedObjectManager; aoqi@0: aoqi@0: import javax.xml.namespace.QName; aoqi@0: import javax.xml.stream.XMLStreamException; aoqi@0: import javax.xml.ws.BindingProvider; aoqi@0: import javax.xml.ws.EndpointReference; aoqi@0: import javax.xml.ws.RespectBindingFeature; aoqi@0: import javax.xml.ws.Response; aoqi@0: import javax.xml.ws.WebServiceException; aoqi@0: import javax.xml.ws.http.HTTPBinding; aoqi@0: import javax.xml.ws.wsaddressing.W3CEndpointReference; aoqi@0: import java.util.ArrayList; aoqi@0: import java.util.Collections; aoqi@0: import java.util.List; aoqi@0: import java.util.Map; aoqi@0: import java.util.Set; aoqi@0: import java.util.concurrent.CopyOnWriteArraySet; aoqi@0: import java.util.concurrent.Executor; aoqi@0: import java.util.logging.Level; aoqi@0: import java.util.logging.Logger; aoqi@0: import javax.management.ObjectName; aoqi@0: aoqi@0: /** aoqi@0: * Base class for stubs, which accept method invocations from aoqi@0: * client applications and pass the message to a {@link Tube} aoqi@0: * for processing. aoqi@0: * aoqi@0: *

aoqi@0: * This class implements the management of pipe instances, aoqi@0: * and most of the {@link BindingProvider} methods. aoqi@0: * aoqi@0: * @author Kohsuke Kawaguchi aoqi@0: */ aoqi@0: public abstract class Stub implements WSBindingProvider, ResponseContextReceiver, ComponentRegistry { aoqi@0: /** aoqi@0: * Internal flag indicating async dispatch should be used even when the aoqi@0: * SyncStartForAsyncInvokeFeature is present on the binding associated aoqi@0: * with a stub. There is no type associated with this property on the aoqi@0: * request context. Its presence is what triggers the 'prevent' behavior. aoqi@0: */ aoqi@0: public static final String PREVENT_SYNC_START_FOR_ASYNC_INVOKE = "com.sun.xml.internal.ws.client.StubRequestSyncStartForAsyncInvoke"; aoqi@0: aoqi@0: /** aoqi@0: * Reuse pipelines as it's expensive to create. aoqi@0: *

aoqi@0: * Set to null when {@link #close() closed}. aoqi@0: */ aoqi@0: private Pool tubes; aoqi@0: aoqi@0: private final Engine engine; aoqi@0: aoqi@0: /** aoqi@0: * The {@link WSServiceDelegate} object that owns us. aoqi@0: */ aoqi@0: protected final WSServiceDelegate owner; aoqi@0: aoqi@0: /** aoqi@0: * Non-null if this stub is configured to talk to an EPR. aoqi@0: *

aoqi@0: * When this field is non-null, its reference parameters are sent as out-bound headers. aoqi@0: * This field can be null even when addressing is enabled, but if the addressing is aoqi@0: * not enabled, this field must be null. aoqi@0: *

aoqi@0: * Unlike endpoint address, we are not letting users to change the EPR, aoqi@0: * as it contains references to services and so on that we don't want to change. aoqi@0: */ aoqi@0: protected aoqi@0: @Nullable aoqi@0: WSEndpointReference endpointReference; aoqi@0: aoqi@0: protected final BindingImpl binding; aoqi@0: aoqi@0: protected final WSPortInfo portInfo; aoqi@0: aoqi@0: /** aoqi@0: * represents AddressingVersion on binding if enabled, otherwise null; aoqi@0: */ aoqi@0: protected AddressingVersion addrVersion; aoqi@0: aoqi@0: public RequestContext requestContext = new RequestContext(); aoqi@0: aoqi@0: private final RequestContext cleanRequestContext; aoqi@0: aoqi@0: /** aoqi@0: * {@link ResponseContext} from the last synchronous operation. aoqi@0: */ aoqi@0: private ResponseContext responseContext; aoqi@0: @Nullable aoqi@0: protected final WSDLPort wsdlPort; aoqi@0: aoqi@0: protected QName portname; aoqi@0: aoqi@0: /** aoqi@0: * {@link Header}s to be added to outbound {@link Packet}. aoqi@0: * The contents is determined by the user. aoqi@0: */ aoqi@0: @Nullable aoqi@0: private volatile Header[] userOutboundHeaders; aoqi@0: aoqi@0: private final aoqi@0: @NotNull aoqi@0: WSDLProperties wsdlProperties; aoqi@0: protected OperationDispatcher operationDispatcher = null; aoqi@0: private final aoqi@0: @NotNull aoqi@0: ManagedObjectManager managedObjectManager; aoqi@0: private boolean managedObjectManagerClosed = false; aoqi@0: aoqi@0: private final Set components = new CopyOnWriteArraySet(); aoqi@0: aoqi@0: /** aoqi@0: * @param master The created stub will send messages to this pipe. aoqi@0: * @param binding As a {@link BindingProvider}, this object will aoqi@0: * return this binding from {@link BindingProvider#getBinding()}. aoqi@0: * @param defaultEndPointAddress The destination of the message. The actual destination aoqi@0: * could be overridden by {@link RequestContext}. aoqi@0: * @param epr To create a stub that sends out reference parameters aoqi@0: * of a specific EPR, give that instance. Otherwise null. aoqi@0: * Its address field will not be used, and that should be given aoqi@0: * separately as the defaultEndPointAddress. aoqi@0: */ aoqi@0: @Deprecated aoqi@0: protected Stub(WSServiceDelegate owner, Tube master, BindingImpl binding, WSDLPort wsdlPort, EndpointAddress defaultEndPointAddress, @Nullable WSEndpointReference epr) { aoqi@0: this(owner, master, null, null, binding, wsdlPort, defaultEndPointAddress, epr); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * @param portname The name of this port aoqi@0: * @param master The created stub will send messages to this pipe. aoqi@0: * @param binding As a {@link BindingProvider}, this object will aoqi@0: * return this binding from {@link BindingProvider#getBinding()}. aoqi@0: * @param defaultEndPointAddress The destination of the message. The actual destination aoqi@0: * could be overridden by {@link RequestContext}. aoqi@0: * @param epr To create a stub that sends out reference parameters aoqi@0: * of a specific EPR, give that instance. Otherwise null. aoqi@0: * Its address field will not be used, and that should be given aoqi@0: * separately as the defaultEndPointAddress. aoqi@0: */ aoqi@0: @Deprecated aoqi@0: protected Stub(QName portname, WSServiceDelegate owner, Tube master, BindingImpl binding, WSDLPort wsdlPort, EndpointAddress defaultEndPointAddress, @Nullable WSEndpointReference epr) { aoqi@0: this(owner, master, null, portname, binding, wsdlPort, defaultEndPointAddress, epr); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * @param portInfo PortInfo for this stub aoqi@0: * @param binding As a {@link BindingProvider}, this object will aoqi@0: * return this binding from {@link BindingProvider#getBinding()}. aoqi@0: * @param master The created stub will send messages to this pipe. aoqi@0: * @param defaultEndPointAddress The destination of the message. The actual destination aoqi@0: * could be overridden by {@link RequestContext}. aoqi@0: * @param epr To create a stub that sends out reference parameters aoqi@0: * of a specific EPR, give that instance. Otherwise null. aoqi@0: * Its address field will not be used, and that should be given aoqi@0: * separately as the defaultEndPointAddress. aoqi@0: */ aoqi@0: protected Stub(WSPortInfo portInfo, BindingImpl binding, Tube master,EndpointAddress defaultEndPointAddress, @Nullable WSEndpointReference epr) { aoqi@0: this((WSServiceDelegate) portInfo.getOwner(), master, portInfo, null, binding,portInfo.getPort(), defaultEndPointAddress, epr); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * @param portInfo PortInfo for this stub aoqi@0: * @param binding As a {@link BindingProvider}, this object will aoqi@0: * return this binding from {@link BindingProvider#getBinding()}. aoqi@0: * @param defaultEndPointAddress The destination of the message. The actual destination aoqi@0: * could be overridden by {@link RequestContext}. aoqi@0: * @param epr To create a stub that sends out reference parameters aoqi@0: * of a specific EPR, give that instance. Otherwise null. aoqi@0: * Its address field will not be used, and that should be given aoqi@0: * separately as the defaultEndPointAddress. aoqi@0: */ aoqi@0: protected Stub(WSPortInfo portInfo, BindingImpl binding, EndpointAddress defaultEndPointAddress, @Nullable WSEndpointReference epr) { aoqi@0: this(portInfo,binding,null, defaultEndPointAddress,epr); aoqi@0: aoqi@0: } aoqi@0: aoqi@0: private Stub(WSServiceDelegate owner, @Nullable Tube master, @Nullable WSPortInfo portInfo, QName portname, BindingImpl binding, @Nullable WSDLPort wsdlPort, EndpointAddress defaultEndPointAddress, @Nullable WSEndpointReference epr) { aoqi@0: Container old = ContainerResolver.getDefault().enterContainer(owner.getContainer()); aoqi@0: try { aoqi@0: this.owner = owner; aoqi@0: this.portInfo = portInfo; aoqi@0: this.wsdlPort = wsdlPort != null ? wsdlPort : (portInfo != null ? portInfo.getPort() : null); aoqi@0: this.portname = portname; aoqi@0: if (portname == null) { aoqi@0: if (portInfo != null) { aoqi@0: this.portname = portInfo.getPortName(); aoqi@0: } else if (wsdlPort != null) { aoqi@0: this.portname = wsdlPort.getName(); aoqi@0: } aoqi@0: } aoqi@0: this.binding = binding; aoqi@0: aoqi@0: ComponentFeature cf = binding.getFeature(ComponentFeature.class); aoqi@0: if (cf != null && Target.STUB.equals(cf.getTarget())) { aoqi@0: components.add(cf.getComponent()); aoqi@0: } aoqi@0: ComponentsFeature csf = binding.getFeature(ComponentsFeature.class); aoqi@0: if (csf != null) { aoqi@0: for (ComponentFeature cfi : csf.getComponentFeatures()) { aoqi@0: if (Target.STUB.equals(cfi.getTarget())) aoqi@0: components.add(cfi.getComponent()); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // if there is an EPR, EPR's address should be used for invocation instead of default address aoqi@0: if (epr != null) { aoqi@0: this.requestContext.setEndPointAddressString(epr.getAddress()); aoqi@0: } else { aoqi@0: this.requestContext.setEndpointAddress(defaultEndPointAddress); aoqi@0: } aoqi@0: this.engine = new Engine(getStringId(), owner.getContainer(), owner.getExecutor()); aoqi@0: this.endpointReference = epr; aoqi@0: wsdlProperties = (wsdlPort == null) ? new WSDLDirectProperties(owner.getServiceName(), portname) : new WSDLPortProperties(wsdlPort); aoqi@0: aoqi@0: this.cleanRequestContext = this.requestContext.copy(); aoqi@0: aoqi@0: // ManagedObjectManager MUST be created before the pipeline aoqi@0: // is constructed. aoqi@0: aoqi@0: managedObjectManager = new MonitorRootClient(this).createManagedObjectManager(this); aoqi@0: aoqi@0: if (master != null) { aoqi@0: this.tubes = new TubePool(master); aoqi@0: } else { aoqi@0: this.tubes = new TubePool(createPipeline(portInfo, binding)); aoqi@0: } aoqi@0: aoqi@0: addrVersion = binding.getAddressingVersion(); aoqi@0: aoqi@0: // This needs to happen after createPipeline. aoqi@0: // TBD: Check if it needs to happen outside the Stub constructor. aoqi@0: managedObjectManager.resumeJMXRegistration(); aoqi@0: } finally { aoqi@0: ContainerResolver.getDefault().exitContainer(old); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Creates a new pipeline for the given port name. aoqi@0: */ aoqi@0: private Tube createPipeline(WSPortInfo portInfo, WSBinding binding) { aoqi@0: //Check all required WSDL extensions are understood aoqi@0: checkAllWSDLExtensionsUnderstood(portInfo, binding); aoqi@0: SEIModel seiModel = null; aoqi@0: Class sei = null; aoqi@0: if (portInfo instanceof SEIPortInfo) { aoqi@0: SEIPortInfo sp = (SEIPortInfo) portInfo; aoqi@0: seiModel = sp.model; aoqi@0: sei = sp.sei; aoqi@0: } aoqi@0: BindingID bindingId = portInfo.getBindingId(); aoqi@0: aoqi@0: TubelineAssembler assembler = TubelineAssemblerFactory.create( aoqi@0: Thread.currentThread().getContextClassLoader(), bindingId, owner.getContainer()); aoqi@0: if (assembler == null) { aoqi@0: throw new WebServiceException("Unable to process bindingID=" + bindingId); // TODO: i18n aoqi@0: } aoqi@0: return assembler.createClient( aoqi@0: new ClientTubeAssemblerContext( aoqi@0: portInfo.getEndpointAddress(), aoqi@0: portInfo.getPort(), aoqi@0: this, binding, owner.getContainer(), ((BindingImpl) binding).createCodec(), seiModel, sei)); aoqi@0: } aoqi@0: aoqi@0: public WSDLPort getWSDLPort() { aoqi@0: return wsdlPort; aoqi@0: } aoqi@0: aoqi@0: public WSService getService() { aoqi@0: return owner; aoqi@0: } aoqi@0: aoqi@0: public Pool getTubes() { aoqi@0: return tubes; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Checks only if RespectBindingFeature is enabled aoqi@0: * checks if all required wsdl extensions in the aoqi@0: * corresponding wsdl:Port are understood when RespectBindingFeature is enabled. aoqi@0: * @throws WebServiceException aoqi@0: * when any wsdl extension that has wsdl:required=true is not understood aoqi@0: */ aoqi@0: private static void checkAllWSDLExtensionsUnderstood(WSPortInfo port, WSBinding binding) { aoqi@0: if (port.getPort() != null && binding.isFeatureEnabled(RespectBindingFeature.class)) { aoqi@0: port.getPort().areRequiredExtensionsUnderstood(); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public WSPortInfo getPortInfo() { aoqi@0: return portInfo; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Nullable when there is no associated WSDL Model aoqi@0: * @return aoqi@0: */ aoqi@0: public aoqi@0: @Nullable aoqi@0: OperationDispatcher getOperationDispatcher() { aoqi@0: if (operationDispatcher == null && wsdlPort != null) { aoqi@0: operationDispatcher = new OperationDispatcher(wsdlPort, binding, null); aoqi@0: } aoqi@0: return operationDispatcher; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Gets the port name that this stub is configured to talk to. aoqi@0: *

aoqi@0: * When {@link #wsdlPort} is non-null, the port name is always aoqi@0: * the same as {@link WSDLPort#getName()}, but this method aoqi@0: * returns a port name even if no WSDL is available for this stub. aoqi@0: */ aoqi@0: protected abstract aoqi@0: @NotNull aoqi@0: QName getPortName(); aoqi@0: aoqi@0: /** aoqi@0: * Gets the service name that this stub is configured to talk to. aoqi@0: *

aoqi@0: * When {@link #wsdlPort} is non-null, the service name is always aoqi@0: * the same as the one that's inferred from {@link WSDLPort#getOwner()}, aoqi@0: * but this method returns a port name even if no WSDL is available for aoqi@0: * this stub. aoqi@0: */ aoqi@0: protected final aoqi@0: @NotNull aoqi@0: QName getServiceName() { aoqi@0: return owner.getServiceName(); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Gets the {@link Executor} to be used for asynchronous method invocations. aoqi@0: *

aoqi@0: * Note that the value this method returns may different from invocations aoqi@0: * to invocations. The caller must not cache. aoqi@0: * aoqi@0: * @return always non-null. aoqi@0: */ aoqi@0: public final Executor getExecutor() { aoqi@0: return owner.getExecutor(); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Passes a message to a pipe for processing. aoqi@0: *

aoqi@0: * Unlike {@link Tube} instances, aoqi@0: * this method is thread-safe and can be invoked from aoqi@0: * multiple threads concurrently. aoqi@0: * aoqi@0: * @param packet The message to be sent to the server aoqi@0: * @param requestContext The {@link RequestContext} when this invocation is originally scheduled. aoqi@0: * This must be the same object as {@link #requestContext} for synchronous aoqi@0: * invocations, but for asynchronous invocations, it needs to be a snapshot aoqi@0: * captured at the point of invocation, to correctly satisfy the spec requirement. aoqi@0: * @param receiver Receives the {@link ResponseContext}. Since the spec requires aoqi@0: * that the asynchronous invocations must not update response context, aoqi@0: * depending on the mode of invocation they have to go to different places. aoqi@0: * So we take a setter that abstracts that away. aoqi@0: */ aoqi@0: protected final Packet process(Packet packet, RequestContext requestContext, ResponseContextReceiver receiver) { aoqi@0: packet.isSynchronousMEP = true; aoqi@0: packet.component = this; aoqi@0: configureRequestPacket(packet, requestContext); aoqi@0: Pool pool = tubes; aoqi@0: if (pool == null) { aoqi@0: throw new WebServiceException("close method has already been invoked"); // TODO: i18n aoqi@0: } aoqi@0: aoqi@0: Fiber fiber = engine.createFiber(); aoqi@0: configureFiber(fiber); aoqi@0: aoqi@0: // then send it away! aoqi@0: Tube tube = pool.take(); aoqi@0: aoqi@0: try { aoqi@0: return fiber.runSync(tube, packet); aoqi@0: } finally { aoqi@0: // this allows us to capture the packet even when the call failed with an exception. aoqi@0: // when the call fails with an exception it's no longer a 'reply' but it may provide some information aoqi@0: // about what went wrong. aoqi@0: aoqi@0: // note that Packet can still be updated after aoqi@0: // ResponseContext is created. aoqi@0: Packet reply = (fiber.getPacket() == null) ? packet : fiber.getPacket(); aoqi@0: receiver.setResponseContext(new ResponseContext(reply)); aoqi@0: aoqi@0: pool.recycle(tube); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: private void configureRequestPacket(Packet packet, RequestContext requestContext) { aoqi@0: // fill in Packet aoqi@0: packet.proxy = this; aoqi@0: packet.handlerConfig = binding.getHandlerConfig(); aoqi@0: aoqi@0: // to make it multi-thread safe we need to first get a stable snapshot aoqi@0: Header[] hl = userOutboundHeaders; aoqi@0: if (hl != null) { aoqi@0: MessageHeaders mh = packet.getMessage().getHeaders(); aoqi@0: for (Header h : hl) { aoqi@0: mh.add(h); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: requestContext.fill(packet, (binding.getAddressingVersion() != null)); aoqi@0: packet.addSatellite(wsdlProperties); aoqi@0: aoqi@0: if (addrVersion != null) { aoqi@0: // populate request WS-Addressing headers aoqi@0: MessageHeaders headerList = packet.getMessage().getHeaders(); aoqi@0: AddressingUtils.fillRequestAddressingHeaders(headerList, wsdlPort, binding, packet); aoqi@0: aoqi@0: aoqi@0: // Spec is not clear on if ReferenceParameters are to be added when addressing is not enabled, aoqi@0: // but the EPR has ReferenceParameters. aoqi@0: // Current approach: Add ReferenceParameters only if addressing enabled. aoqi@0: if (endpointReference != null) { aoqi@0: endpointReference.addReferenceParametersToList(packet.getMessage().getHeaders()); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Passes a message through a {@link Tube}line for processing. The processing happens aoqi@0: * asynchronously and when the response is available, Fiber.CompletionCallback is aoqi@0: * called. The processing could happen on multiple threads. aoqi@0: * aoqi@0: *

aoqi@0: * Unlike {@link Tube} instances, aoqi@0: * this method is thread-safe and can be invoked from aoqi@0: * multiple threads concurrently. aoqi@0: * aoqi@0: * @param receiver The {@link Response} implementation aoqi@0: * @param request The message to be sent to the server aoqi@0: * @param requestContext The {@link RequestContext} when this invocation is originally scheduled. aoqi@0: * This must be the same object as {@link #requestContext} for synchronous aoqi@0: * invocations, but for asynchronous invocations, it needs to be a snapshot aoqi@0: * captured at the point of invocation, to correctly satisfy the spec requirement. aoqi@0: * @param completionCallback Once the processing is done, the callback is invoked. aoqi@0: */ aoqi@0: protected final void processAsync(AsyncResponseImpl receiver, Packet request, RequestContext requestContext, final Fiber.CompletionCallback completionCallback) { aoqi@0: // fill in Packet aoqi@0: request.component = this; aoqi@0: configureRequestPacket(request, requestContext); aoqi@0: aoqi@0: final Pool pool = tubes; aoqi@0: if (pool == null) { aoqi@0: throw new WebServiceException("close method has already been invoked"); // TODO: i18n aoqi@0: } aoqi@0: aoqi@0: final Fiber fiber = engine.createFiber(); aoqi@0: configureFiber(fiber); aoqi@0: aoqi@0: receiver.setCancelable(fiber); aoqi@0: aoqi@0: // check race condition on cancel aoqi@0: if (receiver.isCancelled()) { aoqi@0: return; aoqi@0: } aoqi@0: aoqi@0: FiberContextSwitchInterceptorFactory fcsif = owner.getSPI(FiberContextSwitchInterceptorFactory.class); aoqi@0: if (fcsif != null) { aoqi@0: fiber.addInterceptor(fcsif.create()); aoqi@0: } aoqi@0: aoqi@0: // then send it away! aoqi@0: final Tube tube = pool.take(); aoqi@0: aoqi@0: Fiber.CompletionCallback fiberCallback = new Fiber.CompletionCallback() { aoqi@0: @Override aoqi@0: public void onCompletion(@NotNull Packet response) { aoqi@0: pool.recycle(tube); aoqi@0: completionCallback.onCompletion(response); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public void onCompletion(@NotNull Throwable error) { aoqi@0: // let's not reuse tubes as they might be in a wrong state, so not aoqi@0: // calling pool.recycle() aoqi@0: completionCallback.onCompletion(error); aoqi@0: } aoqi@0: }; aoqi@0: aoqi@0: // Check for SyncStartForAsyncInvokeFeature aoqi@0: aoqi@0: fiber.start(tube, request, fiberCallback, aoqi@0: getBinding().isFeatureEnabled(SyncStartForAsyncFeature.class) && aoqi@0: !requestContext.containsKey(PREVENT_SYNC_START_FOR_ASYNC_INVOKE)); aoqi@0: } aoqi@0: aoqi@0: protected void configureFiber(Fiber fiber) { aoqi@0: // no-op in the base class, but can be used by derived classes to configure the Fiber prior aoqi@0: // to invocation aoqi@0: } aoqi@0: aoqi@0: private static final Logger monitoringLogger = Logger.getLogger(com.sun.xml.internal.ws.util.Constants.LoggingDomain + ".monitoring"); aoqi@0: aoqi@0: @Override aoqi@0: public void close() { aoqi@0: TubePool tp = (TubePool) tubes; aoqi@0: if (tp != null) { aoqi@0: // multi-thread safety of 'close' needs to be considered more carefully. aoqi@0: // some calls might be pending while this method is invoked. Should we aoqi@0: // block until they are complete, or should we abort them (but how?) aoqi@0: Tube p = tp.takeMaster(); aoqi@0: p.preDestroy(); aoqi@0: tubes = null; aoqi@0: } aoqi@0: if (!managedObjectManagerClosed) { aoqi@0: try { aoqi@0: final ObjectName name = managedObjectManager.getObjectName(managedObjectManager.getRoot()); aoqi@0: // The name is null when the MOM is a NOOP. aoqi@0: if (name != null) { aoqi@0: monitoringLogger.log(Level.INFO, "Closing Metro monitoring root: {0}", name); aoqi@0: } aoqi@0: managedObjectManager.close(); aoqi@0: } catch (java.io.IOException e) { aoqi@0: monitoringLogger.log(Level.WARNING, "Ignoring error when closing Managed Object Manager", e); aoqi@0: } aoqi@0: managedObjectManagerClosed = true; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public final WSBinding getBinding() { aoqi@0: return binding; aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public final Map getRequestContext() { aoqi@0: return requestContext.asMap(); aoqi@0: } aoqi@0: aoqi@0: public void resetRequestContext() { aoqi@0: requestContext = cleanRequestContext.copy(); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public final ResponseContext getResponseContext() { aoqi@0: return responseContext; aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public void setResponseContext(ResponseContext rc) { aoqi@0: this.responseContext = rc; aoqi@0: } aoqi@0: aoqi@0: private String getStringId() { aoqi@0: return RuntimeVersion.VERSION + ": Stub for " + getRequestContext().get(BindingProvider.ENDPOINT_ADDRESS_PROPERTY); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public String toString() { aoqi@0: return getStringId(); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public final WSEndpointReference getWSEndpointReference() { aoqi@0: if (binding.getBindingID().equals(HTTPBinding.HTTP_BINDING)) { aoqi@0: throw new java.lang.UnsupportedOperationException( aoqi@0: ClientMessages.UNSUPPORTED_OPERATION("BindingProvider.getEndpointReference(Class class)", "XML/HTTP Binding", "SOAP11 or SOAP12 Binding") aoqi@0: ); aoqi@0: } aoqi@0: aoqi@0: if (endpointReference != null) { aoqi@0: return endpointReference; aoqi@0: } aoqi@0: aoqi@0: String eprAddress = requestContext.getEndpointAddress().toString(); aoqi@0: QName portTypeName = null; aoqi@0: String wsdlAddress = null; aoqi@0: List wsdlEPRExtensions = new ArrayList(); aoqi@0: if (wsdlPort != null) { aoqi@0: portTypeName = wsdlPort.getBinding().getPortTypeName(); aoqi@0: wsdlAddress = eprAddress + "?wsdl"; aoqi@0: aoqi@0: //gather EPRExtensions specified in WSDL. aoqi@0: try { aoqi@0: WSEndpointReference wsdlEpr = wsdlPort.getEPR(); aoqi@0: if (wsdlEpr != null) { aoqi@0: for (WSEndpointReference.EPRExtension extnEl : wsdlEpr.getEPRExtensions()) { aoqi@0: wsdlEPRExtensions.add(new WSEPRExtension( aoqi@0: XMLStreamBuffer.createNewBufferFromXMLStreamReader(extnEl.readAsXMLStreamReader()), extnEl.getQName())); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: } catch (XMLStreamException ex) { aoqi@0: throw new WebServiceException(ex); aoqi@0: } aoqi@0: } aoqi@0: AddressingVersion av = AddressingVersion.W3C; aoqi@0: this.endpointReference = new WSEndpointReference( aoqi@0: av, eprAddress, getServiceName(), getPortName(), portTypeName, null, wsdlAddress, null, wsdlEPRExtensions, null); aoqi@0: aoqi@0: return this.endpointReference; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: @Override aoqi@0: public final W3CEndpointReference getEndpointReference() { aoqi@0: if (binding.getBindingID().equals(HTTPBinding.HTTP_BINDING)) { aoqi@0: throw new java.lang.UnsupportedOperationException( aoqi@0: ClientMessages.UNSUPPORTED_OPERATION("BindingProvider.getEndpointReference()", "XML/HTTP Binding", "SOAP11 or SOAP12 Binding")); aoqi@0: } aoqi@0: return getEndpointReference(W3CEndpointReference.class); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public final T getEndpointReference(Class clazz) { aoqi@0: return getWSEndpointReference().toSpec(clazz); aoqi@0: } aoqi@0: aoqi@0: public aoqi@0: @NotNull aoqi@0: @Override aoqi@0: ManagedObjectManager getManagedObjectManager() { aoqi@0: return managedObjectManager; aoqi@0: } aoqi@0: aoqi@0: // aoqi@0: // aoqi@0: // WSBindingProvider methods aoqi@0: // aoqi@0: // aoqi@0: @Override aoqi@0: public final void setOutboundHeaders(List

headers) { aoqi@0: if (headers == null) { aoqi@0: this.userOutboundHeaders = null; aoqi@0: } else { aoqi@0: for (Header h : headers) { aoqi@0: if (h == null) { aoqi@0: throw new IllegalArgumentException(); aoqi@0: } aoqi@0: } aoqi@0: userOutboundHeaders = headers.toArray(new Header[headers.size()]); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public final void setOutboundHeaders(Header... headers) { aoqi@0: if (headers == null) { aoqi@0: this.userOutboundHeaders = null; aoqi@0: } else { aoqi@0: for (Header h : headers) { aoqi@0: if (h == null) { aoqi@0: throw new IllegalArgumentException(); aoqi@0: } aoqi@0: } aoqi@0: Header[] hl = new Header[headers.length]; aoqi@0: System.arraycopy(headers, 0, hl, 0, headers.length); aoqi@0: userOutboundHeaders = hl; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public final List
getInboundHeaders() { aoqi@0: return Collections.unmodifiableList(((MessageHeaders) aoqi@0: responseContext.get(JAXWSProperties.INBOUND_HEADER_LIST_PROPERTY)).asList()); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public final void setAddress(String address) { aoqi@0: requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, address); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public S getSPI(Class spiType) { aoqi@0: for (Component c : components) { aoqi@0: S s = c.getSPI(spiType); aoqi@0: if (s != null) { aoqi@0: return s; aoqi@0: } aoqi@0: } aoqi@0: return owner.getSPI(spiType); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public Set getComponents() { aoqi@0: return components; aoqi@0: } aoqi@0: }