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