754 lines
30 KiB
Java
754 lines
30 KiB
Java
/*
|
|
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation. Oracle designates this
|
|
* particular file as subject to the "Classpath" exception as provided
|
|
* by Oracle in the LICENSE file that accompanied this code.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*/
|
|
|
|
package com.sun.xml.internal.ws.client;
|
|
|
|
import com.sun.istack.internal.NotNull;
|
|
import com.sun.istack.internal.Nullable;
|
|
import com.sun.xml.internal.stream.buffer.XMLStreamBuffer;
|
|
import com.sun.xml.internal.ws.addressing.WSEPRExtension;
|
|
import com.sun.xml.internal.ws.api.BindingID;
|
|
import com.sun.xml.internal.ws.api.Component;
|
|
import com.sun.xml.internal.ws.api.ComponentFeature;
|
|
import com.sun.xml.internal.ws.api.ComponentFeature.Target;
|
|
import com.sun.xml.internal.ws.api.ComponentRegistry;
|
|
import com.sun.xml.internal.ws.api.ComponentsFeature;
|
|
import com.sun.xml.internal.ws.api.EndpointAddress;
|
|
import com.sun.xml.internal.ws.api.WSBinding;
|
|
import com.sun.xml.internal.ws.api.WSService;
|
|
import com.sun.xml.internal.ws.api.addressing.AddressingVersion;
|
|
import com.sun.xml.internal.ws.api.addressing.WSEndpointReference;
|
|
import com.sun.xml.internal.ws.api.client.WSPortInfo;
|
|
import com.sun.xml.internal.ws.api.message.AddressingUtils;
|
|
import com.sun.xml.internal.ws.api.message.Header;
|
|
import com.sun.xml.internal.ws.api.message.HeaderList;
|
|
import com.sun.xml.internal.ws.api.message.MessageHeaders;
|
|
import com.sun.xml.internal.ws.api.message.Packet;
|
|
import com.sun.xml.internal.ws.api.model.SEIModel;
|
|
import com.sun.xml.internal.ws.api.model.wsdl.WSDLPort;
|
|
import com.sun.xml.internal.ws.api.pipe.ClientTubeAssemblerContext;
|
|
import com.sun.xml.internal.ws.api.pipe.Engine;
|
|
import com.sun.xml.internal.ws.api.pipe.Fiber;
|
|
import com.sun.xml.internal.ws.api.pipe.FiberContextSwitchInterceptorFactory;
|
|
import com.sun.xml.internal.ws.api.pipe.SyncStartForAsyncFeature;
|
|
import com.sun.xml.internal.ws.api.pipe.Tube;
|
|
import com.sun.xml.internal.ws.api.pipe.TubelineAssembler;
|
|
import com.sun.xml.internal.ws.api.pipe.TubelineAssemblerFactory;
|
|
import com.sun.xml.internal.ws.api.server.Container;
|
|
import com.sun.xml.internal.ws.api.server.ContainerResolver;
|
|
import com.sun.xml.internal.ws.binding.BindingImpl;
|
|
import com.sun.xml.internal.ws.developer.JAXWSProperties;
|
|
import com.sun.xml.internal.ws.developer.WSBindingProvider;
|
|
import com.sun.xml.internal.ws.model.wsdl.WSDLDirectProperties;
|
|
import com.sun.xml.internal.ws.model.wsdl.WSDLPortProperties;
|
|
import com.sun.xml.internal.ws.model.wsdl.WSDLProperties;
|
|
import com.sun.xml.internal.ws.resources.ClientMessages;
|
|
import com.sun.xml.internal.ws.util.Pool;
|
|
import com.sun.xml.internal.ws.util.Pool.TubePool;
|
|
import com.sun.xml.internal.ws.util.RuntimeVersion;
|
|
import com.sun.xml.internal.ws.wsdl.OperationDispatcher;
|
|
import com.sun.org.glassfish.gmbal.ManagedObjectManager;
|
|
|
|
import javax.xml.namespace.QName;
|
|
import javax.xml.stream.XMLStreamException;
|
|
import javax.xml.ws.BindingProvider;
|
|
import javax.xml.ws.EndpointReference;
|
|
import javax.xml.ws.RespectBindingFeature;
|
|
import javax.xml.ws.Response;
|
|
import javax.xml.ws.WebServiceException;
|
|
import javax.xml.ws.http.HTTPBinding;
|
|
import javax.xml.ws.wsaddressing.W3CEndpointReference;
|
|
import java.util.ArrayList;
|
|
import java.util.Collections;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
import java.util.concurrent.CopyOnWriteArraySet;
|
|
import java.util.concurrent.Executor;
|
|
import java.util.logging.Level;
|
|
import java.util.logging.Logger;
|
|
import javax.management.ObjectName;
|
|
|
|
/**
|
|
* Base class for stubs, which accept method invocations from
|
|
* client applications and pass the message to a {@link Tube}
|
|
* for processing.
|
|
*
|
|
* <p>
|
|
* This class implements the management of pipe instances,
|
|
* and most of the {@link BindingProvider} methods.
|
|
*
|
|
* @author Kohsuke Kawaguchi
|
|
*/
|
|
public abstract class Stub implements WSBindingProvider, ResponseContextReceiver, ComponentRegistry {
|
|
/**
|
|
* Internal flag indicating async dispatch should be used even when the
|
|
* SyncStartForAsyncInvokeFeature is present on the binding associated
|
|
* with a stub. There is no type associated with this property on the
|
|
* request context. Its presence is what triggers the 'prevent' behavior.
|
|
*/
|
|
public static final String PREVENT_SYNC_START_FOR_ASYNC_INVOKE = "com.sun.xml.internal.ws.client.StubRequestSyncStartForAsyncInvoke";
|
|
|
|
/**
|
|
* Reuse pipelines as it's expensive to create.
|
|
* <p>
|
|
* Set to null when {@link #close() closed}.
|
|
*/
|
|
private Pool<Tube> tubes;
|
|
|
|
private final Engine engine;
|
|
|
|
/**
|
|
* The {@link WSServiceDelegate} object that owns us.
|
|
*/
|
|
protected final WSServiceDelegate owner;
|
|
|
|
/**
|
|
* Non-null if this stub is configured to talk to an EPR.
|
|
* <p>
|
|
* When this field is non-null, its reference parameters are sent as out-bound headers.
|
|
* This field can be null even when addressing is enabled, but if the addressing is
|
|
* not enabled, this field must be null.
|
|
* <p>
|
|
* Unlike endpoint address, we are not letting users to change the EPR,
|
|
* as it contains references to services and so on that we don't want to change.
|
|
*/
|
|
protected
|
|
@Nullable
|
|
WSEndpointReference endpointReference;
|
|
|
|
protected final BindingImpl binding;
|
|
|
|
protected final WSPortInfo portInfo;
|
|
|
|
/**
|
|
* represents AddressingVersion on binding if enabled, otherwise null;
|
|
*/
|
|
protected AddressingVersion addrVersion;
|
|
|
|
public RequestContext requestContext = new RequestContext();
|
|
|
|
private final RequestContext cleanRequestContext;
|
|
|
|
/**
|
|
* {@link ResponseContext} from the last synchronous operation.
|
|
*/
|
|
private ResponseContext responseContext;
|
|
@Nullable
|
|
protected final WSDLPort wsdlPort;
|
|
|
|
protected QName portname;
|
|
|
|
/**
|
|
* {@link Header}s to be added to outbound {@link Packet}.
|
|
* The contents is determined by the user.
|
|
*/
|
|
@Nullable
|
|
private volatile Header[] userOutboundHeaders;
|
|
|
|
private final
|
|
@NotNull
|
|
WSDLProperties wsdlProperties;
|
|
protected OperationDispatcher operationDispatcher = null;
|
|
private final
|
|
@NotNull
|
|
ManagedObjectManager managedObjectManager;
|
|
private boolean managedObjectManagerClosed = false;
|
|
|
|
private final Set<Component> components = new CopyOnWriteArraySet<Component>();
|
|
|
|
/**
|
|
* @param master The created stub will send messages to this pipe.
|
|
* @param binding As a {@link BindingProvider}, this object will
|
|
* return this binding from {@link BindingProvider#getBinding()}.
|
|
* @param defaultEndPointAddress The destination of the message. The actual destination
|
|
* could be overridden by {@link RequestContext}.
|
|
* @param epr To create a stub that sends out reference parameters
|
|
* of a specific EPR, give that instance. Otherwise null.
|
|
* Its address field will not be used, and that should be given
|
|
* separately as the <tt>defaultEndPointAddress</tt>.
|
|
*/
|
|
@Deprecated
|
|
protected Stub(WSServiceDelegate owner, Tube master, BindingImpl binding, WSDLPort wsdlPort, EndpointAddress defaultEndPointAddress, @Nullable WSEndpointReference epr) {
|
|
this(owner, master, null, null, binding, wsdlPort, defaultEndPointAddress, epr);
|
|
}
|
|
|
|
/**
|
|
* @param portname The name of this port
|
|
* @param master The created stub will send messages to this pipe.
|
|
* @param binding As a {@link BindingProvider}, this object will
|
|
* return this binding from {@link BindingProvider#getBinding()}.
|
|
* @param defaultEndPointAddress The destination of the message. The actual destination
|
|
* could be overridden by {@link RequestContext}.
|
|
* @param epr To create a stub that sends out reference parameters
|
|
* of a specific EPR, give that instance. Otherwise null.
|
|
* Its address field will not be used, and that should be given
|
|
* separately as the <tt>defaultEndPointAddress</tt>.
|
|
*/
|
|
@Deprecated
|
|
protected Stub(QName portname, WSServiceDelegate owner, Tube master, BindingImpl binding, WSDLPort wsdlPort, EndpointAddress defaultEndPointAddress, @Nullable WSEndpointReference epr) {
|
|
this(owner, master, null, portname, binding, wsdlPort, defaultEndPointAddress, epr);
|
|
}
|
|
|
|
/**
|
|
* @param portInfo PortInfo for this stub
|
|
* @param binding As a {@link BindingProvider}, this object will
|
|
* return this binding from {@link BindingProvider#getBinding()}.
|
|
* @param master The created stub will send messages to this pipe.
|
|
* @param defaultEndPointAddress The destination of the message. The actual destination
|
|
* could be overridden by {@link RequestContext}.
|
|
* @param epr To create a stub that sends out reference parameters
|
|
* of a specific EPR, give that instance. Otherwise null.
|
|
* Its address field will not be used, and that should be given
|
|
* separately as the <tt>defaultEndPointAddress</tt>.
|
|
*/
|
|
protected Stub(WSPortInfo portInfo, BindingImpl binding, Tube master,EndpointAddress defaultEndPointAddress, @Nullable WSEndpointReference epr) {
|
|
this((WSServiceDelegate) portInfo.getOwner(), master, portInfo, null, binding,portInfo.getPort(), defaultEndPointAddress, epr);
|
|
}
|
|
|
|
/**
|
|
* @param portInfo PortInfo for this stub
|
|
* @param binding As a {@link BindingProvider}, this object will
|
|
* return this binding from {@link BindingProvider#getBinding()}.
|
|
* @param defaultEndPointAddress The destination of the message. The actual destination
|
|
* could be overridden by {@link RequestContext}.
|
|
* @param epr To create a stub that sends out reference parameters
|
|
* of a specific EPR, give that instance. Otherwise null.
|
|
* Its address field will not be used, and that should be given
|
|
* separately as the <tt>defaultEndPointAddress</tt>.
|
|
*/
|
|
protected Stub(WSPortInfo portInfo, BindingImpl binding, EndpointAddress defaultEndPointAddress, @Nullable WSEndpointReference epr) {
|
|
this(portInfo,binding,null, defaultEndPointAddress,epr);
|
|
|
|
}
|
|
|
|
private Stub(WSServiceDelegate owner, @Nullable Tube master, @Nullable WSPortInfo portInfo, QName portname, BindingImpl binding, @Nullable WSDLPort wsdlPort, EndpointAddress defaultEndPointAddress, @Nullable WSEndpointReference epr) {
|
|
Container old = ContainerResolver.getDefault().enterContainer(owner.getContainer());
|
|
try {
|
|
this.owner = owner;
|
|
this.portInfo = portInfo;
|
|
this.wsdlPort = wsdlPort != null ? wsdlPort : (portInfo != null ? portInfo.getPort() : null);
|
|
this.portname = portname;
|
|
if (portname == null) {
|
|
if (portInfo != null) {
|
|
this.portname = portInfo.getPortName();
|
|
} else if (wsdlPort != null) {
|
|
this.portname = wsdlPort.getName();
|
|
}
|
|
}
|
|
this.binding = binding;
|
|
|
|
ComponentFeature cf = binding.getFeature(ComponentFeature.class);
|
|
if (cf != null && Target.STUB.equals(cf.getTarget())) {
|
|
components.add(cf.getComponent());
|
|
}
|
|
ComponentsFeature csf = binding.getFeature(ComponentsFeature.class);
|
|
if (csf != null) {
|
|
for (ComponentFeature cfi : csf.getComponentFeatures()) {
|
|
if (Target.STUB.equals(cfi.getTarget()))
|
|
components.add(cfi.getComponent());
|
|
}
|
|
}
|
|
|
|
// if there is an EPR, EPR's address should be used for invocation instead of default address
|
|
if (epr != null) {
|
|
this.requestContext.setEndPointAddressString(epr.getAddress());
|
|
} else {
|
|
this.requestContext.setEndpointAddress(defaultEndPointAddress);
|
|
}
|
|
this.engine = new Engine(getStringId(), owner.getContainer(), owner.getExecutor());
|
|
this.endpointReference = epr;
|
|
wsdlProperties = (wsdlPort == null) ? new WSDLDirectProperties(owner.getServiceName(), portname) : new WSDLPortProperties(wsdlPort);
|
|
|
|
this.cleanRequestContext = this.requestContext.copy();
|
|
|
|
// ManagedObjectManager MUST be created before the pipeline
|
|
// is constructed.
|
|
|
|
managedObjectManager = new MonitorRootClient(this).createManagedObjectManager(this);
|
|
|
|
if (master != null) {
|
|
this.tubes = new TubePool(master);
|
|
} else {
|
|
this.tubes = new TubePool(createPipeline(portInfo, binding));
|
|
}
|
|
|
|
addrVersion = binding.getAddressingVersion();
|
|
|
|
// This needs to happen after createPipeline.
|
|
// TBD: Check if it needs to happen outside the Stub constructor.
|
|
managedObjectManager.resumeJMXRegistration();
|
|
} finally {
|
|
ContainerResolver.getDefault().exitContainer(old);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Creates a new pipeline for the given port name.
|
|
*/
|
|
private Tube createPipeline(WSPortInfo portInfo, WSBinding binding) {
|
|
//Check all required WSDL extensions are understood
|
|
checkAllWSDLExtensionsUnderstood(portInfo, binding);
|
|
SEIModel seiModel = null;
|
|
Class sei = null;
|
|
if (portInfo instanceof SEIPortInfo) {
|
|
SEIPortInfo sp = (SEIPortInfo) portInfo;
|
|
seiModel = sp.model;
|
|
sei = sp.sei;
|
|
}
|
|
BindingID bindingId = portInfo.getBindingId();
|
|
|
|
TubelineAssembler assembler = TubelineAssemblerFactory.create(
|
|
Thread.currentThread().getContextClassLoader(), bindingId, owner.getContainer());
|
|
if (assembler == null) {
|
|
throw new WebServiceException("Unable to process bindingID=" + bindingId); // TODO: i18n
|
|
}
|
|
return assembler.createClient(
|
|
new ClientTubeAssemblerContext(
|
|
portInfo.getEndpointAddress(),
|
|
portInfo.getPort(),
|
|
this, binding, owner.getContainer(), ((BindingImpl) binding).createCodec(), seiModel, sei));
|
|
}
|
|
|
|
public WSDLPort getWSDLPort() {
|
|
return wsdlPort;
|
|
}
|
|
|
|
public WSService getService() {
|
|
return owner;
|
|
}
|
|
|
|
public Pool<Tube> getTubes() {
|
|
return tubes;
|
|
}
|
|
|
|
/**
|
|
* Checks only if RespectBindingFeature is enabled
|
|
* checks if all required wsdl extensions in the
|
|
* corresponding wsdl:Port are understood when RespectBindingFeature is enabled.
|
|
* @throws WebServiceException
|
|
* when any wsdl extension that has wsdl:required=true is not understood
|
|
*/
|
|
private static void checkAllWSDLExtensionsUnderstood(WSPortInfo port, WSBinding binding) {
|
|
if (port.getPort() != null && binding.isFeatureEnabled(RespectBindingFeature.class)) {
|
|
port.getPort().areRequiredExtensionsUnderstood();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public WSPortInfo getPortInfo() {
|
|
return portInfo;
|
|
}
|
|
|
|
/**
|
|
* Nullable when there is no associated WSDL Model
|
|
* @return
|
|
*/
|
|
public
|
|
@Nullable
|
|
OperationDispatcher getOperationDispatcher() {
|
|
if (operationDispatcher == null && wsdlPort != null) {
|
|
operationDispatcher = new OperationDispatcher(wsdlPort, binding, null);
|
|
}
|
|
return operationDispatcher;
|
|
}
|
|
|
|
/**
|
|
* Gets the port name that this stub is configured to talk to.
|
|
* <p>
|
|
* When {@link #wsdlPort} is non-null, the port name is always
|
|
* the same as {@link WSDLPort#getName()}, but this method
|
|
* returns a port name even if no WSDL is available for this stub.
|
|
*/
|
|
protected abstract
|
|
@NotNull
|
|
QName getPortName();
|
|
|
|
/**
|
|
* Gets the service name that this stub is configured to talk to.
|
|
* <p>
|
|
* When {@link #wsdlPort} is non-null, the service name is always
|
|
* the same as the one that's inferred from {@link WSDLPort#getOwner()},
|
|
* but this method returns a port name even if no WSDL is available for
|
|
* this stub.
|
|
*/
|
|
protected final
|
|
@NotNull
|
|
QName getServiceName() {
|
|
return owner.getServiceName();
|
|
}
|
|
|
|
/**
|
|
* Gets the {@link Executor} to be used for asynchronous method invocations.
|
|
* <p>
|
|
* Note that the value this method returns may different from invocations
|
|
* to invocations. The caller must not cache.
|
|
*
|
|
* @return always non-null.
|
|
*/
|
|
public final Executor getExecutor() {
|
|
return owner.getExecutor();
|
|
}
|
|
|
|
/**
|
|
* Passes a message to a pipe for processing.
|
|
* <p>
|
|
* Unlike {@link Tube} instances,
|
|
* this method is thread-safe and can be invoked from
|
|
* multiple threads concurrently.
|
|
*
|
|
* @param packet The message to be sent to the server
|
|
* @param requestContext The {@link RequestContext} when this invocation is originally scheduled.
|
|
* This must be the same object as {@link #requestContext} for synchronous
|
|
* invocations, but for asynchronous invocations, it needs to be a snapshot
|
|
* captured at the point of invocation, to correctly satisfy the spec requirement.
|
|
* @param receiver Receives the {@link ResponseContext}. Since the spec requires
|
|
* that the asynchronous invocations must not update response context,
|
|
* depending on the mode of invocation they have to go to different places.
|
|
* So we take a setter that abstracts that away.
|
|
*/
|
|
protected final Packet process(Packet packet, RequestContext requestContext, ResponseContextReceiver receiver) {
|
|
packet.isSynchronousMEP = true;
|
|
packet.component = this;
|
|
configureRequestPacket(packet, requestContext);
|
|
Pool<Tube> pool = tubes;
|
|
if (pool == null) {
|
|
throw new WebServiceException("close method has already been invoked"); // TODO: i18n
|
|
}
|
|
|
|
Fiber fiber = engine.createFiber();
|
|
configureFiber(fiber);
|
|
|
|
// then send it away!
|
|
Tube tube = pool.take();
|
|
|
|
try {
|
|
return fiber.runSync(tube, packet);
|
|
} finally {
|
|
// this allows us to capture the packet even when the call failed with an exception.
|
|
// when the call fails with an exception it's no longer a 'reply' but it may provide some information
|
|
// about what went wrong.
|
|
|
|
// note that Packet can still be updated after
|
|
// ResponseContext is created.
|
|
Packet reply = (fiber.getPacket() == null) ? packet : fiber.getPacket();
|
|
receiver.setResponseContext(new ResponseContext(reply));
|
|
|
|
pool.recycle(tube);
|
|
}
|
|
}
|
|
|
|
private void configureRequestPacket(Packet packet, RequestContext requestContext) {
|
|
// fill in Packet
|
|
packet.proxy = this;
|
|
packet.handlerConfig = binding.getHandlerConfig();
|
|
|
|
// to make it multi-thread safe we need to first get a stable snapshot
|
|
Header[] hl = userOutboundHeaders;
|
|
if (hl != null) {
|
|
MessageHeaders mh = packet.getMessage().getHeaders();
|
|
for (Header h : hl) {
|
|
mh.add(h);
|
|
}
|
|
}
|
|
|
|
requestContext.fill(packet, (binding.getAddressingVersion() != null));
|
|
packet.addSatellite(wsdlProperties);
|
|
|
|
if (addrVersion != null) {
|
|
// populate request WS-Addressing headers
|
|
MessageHeaders headerList = packet.getMessage().getHeaders();
|
|
AddressingUtils.fillRequestAddressingHeaders(headerList, wsdlPort, binding, packet);
|
|
|
|
|
|
// Spec is not clear on if ReferenceParameters are to be added when addressing is not enabled,
|
|
// but the EPR has ReferenceParameters.
|
|
// Current approach: Add ReferenceParameters only if addressing enabled.
|
|
if (endpointReference != null) {
|
|
endpointReference.addReferenceParametersToList(packet.getMessage().getHeaders());
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Passes a message through a {@link Tube}line for processing. The processing happens
|
|
* asynchronously and when the response is available, Fiber.CompletionCallback is
|
|
* called. The processing could happen on multiple threads.
|
|
*
|
|
* <p>
|
|
* Unlike {@link Tube} instances,
|
|
* this method is thread-safe and can be invoked from
|
|
* multiple threads concurrently.
|
|
*
|
|
* @param receiver The {@link Response} implementation
|
|
* @param request The message to be sent to the server
|
|
* @param requestContext The {@link RequestContext} when this invocation is originally scheduled.
|
|
* This must be the same object as {@link #requestContext} for synchronous
|
|
* invocations, but for asynchronous invocations, it needs to be a snapshot
|
|
* captured at the point of invocation, to correctly satisfy the spec requirement.
|
|
* @param completionCallback Once the processing is done, the callback is invoked.
|
|
*/
|
|
protected final void processAsync(AsyncResponseImpl<?> receiver, Packet request, RequestContext requestContext, final Fiber.CompletionCallback completionCallback) {
|
|
// fill in Packet
|
|
request.component = this;
|
|
configureRequestPacket(request, requestContext);
|
|
|
|
final Pool<Tube> pool = tubes;
|
|
if (pool == null) {
|
|
throw new WebServiceException("close method has already been invoked"); // TODO: i18n
|
|
}
|
|
|
|
final Fiber fiber = engine.createFiber();
|
|
configureFiber(fiber);
|
|
|
|
receiver.setCancelable(fiber);
|
|
|
|
// check race condition on cancel
|
|
if (receiver.isCancelled()) {
|
|
return;
|
|
}
|
|
|
|
FiberContextSwitchInterceptorFactory fcsif = owner.getSPI(FiberContextSwitchInterceptorFactory.class);
|
|
if (fcsif != null) {
|
|
fiber.addInterceptor(fcsif.create());
|
|
}
|
|
|
|
// then send it away!
|
|
final Tube tube = pool.take();
|
|
|
|
Fiber.CompletionCallback fiberCallback = new Fiber.CompletionCallback() {
|
|
@Override
|
|
public void onCompletion(@NotNull Packet response) {
|
|
pool.recycle(tube);
|
|
completionCallback.onCompletion(response);
|
|
}
|
|
|
|
@Override
|
|
public void onCompletion(@NotNull Throwable error) {
|
|
// let's not reuse tubes as they might be in a wrong state, so not
|
|
// calling pool.recycle()
|
|
completionCallback.onCompletion(error);
|
|
}
|
|
};
|
|
|
|
// Check for SyncStartForAsyncInvokeFeature
|
|
|
|
fiber.start(tube, request, fiberCallback,
|
|
getBinding().isFeatureEnabled(SyncStartForAsyncFeature.class) &&
|
|
!requestContext.containsKey(PREVENT_SYNC_START_FOR_ASYNC_INVOKE));
|
|
}
|
|
|
|
protected void configureFiber(Fiber fiber) {
|
|
// no-op in the base class, but can be used by derived classes to configure the Fiber prior
|
|
// to invocation
|
|
}
|
|
|
|
private static final Logger monitoringLogger = Logger.getLogger(com.sun.xml.internal.ws.util.Constants.LoggingDomain + ".monitoring");
|
|
|
|
@Override
|
|
public void close() {
|
|
TubePool tp = (TubePool) tubes;
|
|
if (tp != null) {
|
|
// multi-thread safety of 'close' needs to be considered more carefully.
|
|
// some calls might be pending while this method is invoked. Should we
|
|
// block until they are complete, or should we abort them (but how?)
|
|
Tube p = tp.takeMaster();
|
|
p.preDestroy();
|
|
tubes = null;
|
|
}
|
|
if (!managedObjectManagerClosed) {
|
|
try {
|
|
final ObjectName name = managedObjectManager.getObjectName(managedObjectManager.getRoot());
|
|
// The name is null when the MOM is a NOOP.
|
|
if (name != null) {
|
|
monitoringLogger.log(Level.INFO, "Closing Metro monitoring root: {0}", name);
|
|
}
|
|
managedObjectManager.close();
|
|
} catch (java.io.IOException e) {
|
|
monitoringLogger.log(Level.WARNING, "Ignoring error when closing Managed Object Manager", e);
|
|
}
|
|
managedObjectManagerClosed = true;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public final WSBinding getBinding() {
|
|
return binding;
|
|
}
|
|
|
|
@Override
|
|
public final Map<String, Object> getRequestContext() {
|
|
return requestContext.asMap();
|
|
}
|
|
|
|
public void resetRequestContext() {
|
|
requestContext = cleanRequestContext.copy();
|
|
}
|
|
|
|
@Override
|
|
public final ResponseContext getResponseContext() {
|
|
return responseContext;
|
|
}
|
|
|
|
@Override
|
|
public void setResponseContext(ResponseContext rc) {
|
|
this.responseContext = rc;
|
|
}
|
|
|
|
private String getStringId() {
|
|
return RuntimeVersion.VERSION + ": Stub for " + getRequestContext().get(BindingProvider.ENDPOINT_ADDRESS_PROPERTY);
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return getStringId();
|
|
}
|
|
|
|
@Override
|
|
public final WSEndpointReference getWSEndpointReference() {
|
|
if (binding.getBindingID().equals(HTTPBinding.HTTP_BINDING)) {
|
|
throw new java.lang.UnsupportedOperationException(
|
|
ClientMessages.UNSUPPORTED_OPERATION("BindingProvider.getEndpointReference(Class<T> class)", "XML/HTTP Binding", "SOAP11 or SOAP12 Binding")
|
|
);
|
|
}
|
|
|
|
if (endpointReference != null) {
|
|
return endpointReference;
|
|
}
|
|
|
|
String eprAddress = requestContext.getEndpointAddress().toString();
|
|
QName portTypeName = null;
|
|
String wsdlAddress = null;
|
|
List<WSEndpointReference.EPRExtension> wsdlEPRExtensions = new ArrayList<WSEndpointReference.EPRExtension>();
|
|
if (wsdlPort != null) {
|
|
portTypeName = wsdlPort.getBinding().getPortTypeName();
|
|
wsdlAddress = eprAddress + "?wsdl";
|
|
|
|
//gather EPRExtensions specified in WSDL.
|
|
try {
|
|
WSEndpointReference wsdlEpr = wsdlPort.getEPR();
|
|
if (wsdlEpr != null) {
|
|
for (WSEndpointReference.EPRExtension extnEl : wsdlEpr.getEPRExtensions()) {
|
|
wsdlEPRExtensions.add(new WSEPRExtension(
|
|
XMLStreamBuffer.createNewBufferFromXMLStreamReader(extnEl.readAsXMLStreamReader()), extnEl.getQName()));
|
|
}
|
|
}
|
|
|
|
} catch (XMLStreamException ex) {
|
|
throw new WebServiceException(ex);
|
|
}
|
|
}
|
|
AddressingVersion av = AddressingVersion.W3C;
|
|
this.endpointReference = new WSEndpointReference(
|
|
av, eprAddress, getServiceName(), getPortName(), portTypeName, null, wsdlAddress, null, wsdlEPRExtensions, null);
|
|
|
|
return this.endpointReference;
|
|
}
|
|
|
|
|
|
@Override
|
|
public final W3CEndpointReference getEndpointReference() {
|
|
if (binding.getBindingID().equals(HTTPBinding.HTTP_BINDING)) {
|
|
throw new java.lang.UnsupportedOperationException(
|
|
ClientMessages.UNSUPPORTED_OPERATION("BindingProvider.getEndpointReference()", "XML/HTTP Binding", "SOAP11 or SOAP12 Binding"));
|
|
}
|
|
return getEndpointReference(W3CEndpointReference.class);
|
|
}
|
|
|
|
@Override
|
|
public final <T extends EndpointReference> T getEndpointReference(Class<T> clazz) {
|
|
return getWSEndpointReference().toSpec(clazz);
|
|
}
|
|
|
|
public
|
|
@NotNull
|
|
@Override
|
|
ManagedObjectManager getManagedObjectManager() {
|
|
return managedObjectManager;
|
|
}
|
|
|
|
//
|
|
//
|
|
// WSBindingProvider methods
|
|
//
|
|
//
|
|
@Override
|
|
public final void setOutboundHeaders(List<Header> headers) {
|
|
if (headers == null) {
|
|
this.userOutboundHeaders = null;
|
|
} else {
|
|
for (Header h : headers) {
|
|
if (h == null) {
|
|
throw new IllegalArgumentException();
|
|
}
|
|
}
|
|
userOutboundHeaders = headers.toArray(new Header[headers.size()]);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public final void setOutboundHeaders(Header... headers) {
|
|
if (headers == null) {
|
|
this.userOutboundHeaders = null;
|
|
} else {
|
|
for (Header h : headers) {
|
|
if (h == null) {
|
|
throw new IllegalArgumentException();
|
|
}
|
|
}
|
|
Header[] hl = new Header[headers.length];
|
|
System.arraycopy(headers, 0, hl, 0, headers.length);
|
|
userOutboundHeaders = hl;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public final List<Header> getInboundHeaders() {
|
|
return Collections.unmodifiableList(((MessageHeaders)
|
|
responseContext.get(JAXWSProperties.INBOUND_HEADER_LIST_PROPERTY)).asList());
|
|
}
|
|
|
|
@Override
|
|
public final void setAddress(String address) {
|
|
requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, address);
|
|
}
|
|
|
|
@Override
|
|
public <S> S getSPI(Class<S> spiType) {
|
|
for (Component c : components) {
|
|
S s = c.getSPI(spiType);
|
|
if (s != null) {
|
|
return s;
|
|
}
|
|
}
|
|
return owner.getSPI(spiType);
|
|
}
|
|
|
|
@Override
|
|
public Set<Component> getComponents() {
|
|
return components;
|
|
}
|
|
}
|