src/share/jaxws_classes/com/sun/xml/internal/ws/client/Stub.java

Tue, 09 Apr 2013 14:51:13 +0100

author
alanb
date
Tue, 09 Apr 2013 14:51:13 +0100
changeset 368
0989ad8c0860
parent 286
f50545b5e2f1
child 408
b0610cd08440
permissions
-rw-r--r--

8010393: Update JAX-WS RI to 2.2.9-b12941
Reviewed-by: alanb, erikj
Contributed-by: miroslav.kos@oracle.com, martin.grebac@oracle.com

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

mercurial