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

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

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

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

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

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

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

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

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

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

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