1 /* 2 * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.xml.internal.ws.client; 27 28 import com.sun.istack.internal.NotNull; 29 import com.sun.istack.internal.Nullable; 30 import com.sun.xml.internal.ws.Closeable; 31 import com.sun.xml.internal.ws.api.BindingID; 32 import com.sun.xml.internal.ws.api.ComponentFeature; 33 import com.sun.xml.internal.ws.api.ComponentsFeature; 34 import com.sun.xml.internal.ws.api.ComponentFeature.Target; 35 import com.sun.xml.internal.ws.api.EndpointAddress; 36 import com.sun.xml.internal.ws.api.WSService; 37 import com.sun.xml.internal.ws.api.addressing.WSEndpointReference; 38 import com.sun.xml.internal.ws.api.client.ServiceInterceptor; 39 import com.sun.xml.internal.ws.api.client.ServiceInterceptorFactory; 40 import com.sun.xml.internal.ws.api.databinding.DatabindingConfig; 41 import com.sun.xml.internal.ws.api.databinding.DatabindingFactory; 42 import com.sun.xml.internal.ws.api.databinding.MetadataReader; 43 import com.sun.xml.internal.ws.api.model.SEIModel; 44 import com.sun.xml.internal.ws.api.model.wsdl.WSDLModel; 45 import com.sun.xml.internal.ws.api.model.wsdl.WSDLPort; 46 import com.sun.xml.internal.ws.api.model.wsdl.WSDLService; 47 import com.sun.xml.internal.ws.api.pipe.Stubs; 48 import com.sun.xml.internal.ws.api.server.Container; 49 import com.sun.xml.internal.ws.api.server.ContainerResolver; 50 import com.sun.xml.internal.ws.api.wsdl.parser.WSDLParserExtension; 51 import com.sun.xml.internal.ws.binding.BindingImpl; 52 import com.sun.xml.internal.ws.binding.WebServiceFeatureList; 53 import com.sun.xml.internal.ws.client.HandlerConfigurator.AnnotationConfigurator; 54 import com.sun.xml.internal.ws.client.HandlerConfigurator.HandlerResolverImpl; 55 import com.sun.xml.internal.ws.client.sei.SEIStub; 56 import com.sun.xml.internal.ws.developer.MemberSubmissionAddressingFeature; 57 import com.sun.xml.internal.ws.developer.UsesJAXBContextFeature; 58 import com.sun.xml.internal.ws.developer.WSBindingProvider; 59 import com.sun.xml.internal.ws.model.RuntimeModeler; 60 import com.sun.xml.internal.ws.model.SOAPSEIModel; 61 import com.sun.xml.internal.ws.resources.ClientMessages; 62 import com.sun.xml.internal.ws.resources.DispatchMessages; 63 import com.sun.xml.internal.ws.resources.ProviderApiMessages; 64 import com.sun.xml.internal.ws.util.JAXWSUtils; 65 import com.sun.xml.internal.ws.util.ServiceConfigurationError; 66 import com.sun.xml.internal.ws.util.ServiceFinder; 67 import com.sun.xml.internal.ws.wsdl.parser.RuntimeWSDLParser; 68 69 import org.xml.sax.EntityResolver; 70 import org.xml.sax.SAXException; 71 72 import javax.jws.HandlerChain; 73 import javax.jws.WebService; 74 import javax.xml.bind.JAXBContext; 75 import javax.xml.namespace.QName; 76 import javax.xml.stream.XMLStreamException; 77 import javax.xml.transform.Source; 78 import javax.xml.transform.stream.StreamSource; 79 import javax.xml.ws.BindingProvider; 80 import javax.xml.ws.Dispatch; 81 import javax.xml.ws.EndpointReference; 82 import javax.xml.ws.Service; 83 import javax.xml.ws.WebServiceClient; 84 import javax.xml.ws.WebServiceException; 85 import javax.xml.ws.WebServiceFeature; 86 import javax.xml.ws.handler.HandlerResolver; 87 import javax.xml.ws.soap.AddressingFeature; 88 89 import java.io.IOException; 90 import java.lang.reflect.InvocationHandler; 91 import java.lang.reflect.Proxy; 92 import java.net.MalformedURLException; 93 import java.net.URL; 94 import java.security.AccessController; 95 import java.security.PrivilegedAction; 96 import java.util.Collection; 97 import java.util.HashMap; 98 import java.util.HashSet; 99 import java.util.Iterator; 100 import java.util.Map; 101 import java.util.Set; 102 import java.util.concurrent.Executor; 103 import java.util.concurrent.ThreadFactory; 104 105 import static com.sun.xml.internal.ws.util.xml.XmlUtil.createDefaultCatalogResolver; 106 107 /** 108 * <code>Service</code> objects provide the client view of a Web service. 109 * 110 * <p><code>Service</code> acts as a factory of the following: 111 * <ul> 112 * <li>Proxies for a target service endpoint. 113 * <li>Instances of <code>javax.xml.ws.Dispatch</code> for 114 * dynamic message-oriented invocation of a remote 115 * operation. 116 * </li> 117 * 118 * <p>The ports available on a service can be enumerated using the 119 * <code>getPorts</code> method. Alternatively, you can pass a 120 * service endpoint interface to the unary <code>getPort</code> method 121 * and let the runtime select a compatible port. 122 * 123 * <p>Handler chains for all the objects created by a <code>Service</code> 124 * can be set by means of the provided <code>HandlerRegistry</code>. 125 * 126 * <p>An <code>Executor</code> may be set on the service in order 127 * to gain better control over the threads used to dispatch asynchronous 128 * callbacks. For instance, thread pooling with certain parameters 129 * can be enabled by creating a <code>ThreadPoolExecutor</code> and 130 * registering it with the service. 131 * 132 * @author WS Development Team 133 * @see Executor 134 * @since JAX-WS 2.0 135 */ 136 public class WSServiceDelegate extends WSService { 137 /** 138 * All ports. 139 * <p> 140 * This includes ports statically known to WSDL, as well as 141 * ones that are dynamically added 142 * through {@link #addPort(QName, String, String)}. 143 * <p> 144 * For statically known ports we'll have {@link SEIPortInfo}. 145 * For dynamically added ones we'll have {@link PortInfo}. 146 */ 147 private final Map<QName, PortInfo> ports = new HashMap<QName, PortInfo>(); 148 // For monitoring 149 protected Map<QName, PortInfo> getQNameToPortInfoMap() { return ports; } 150 151 /** 152 * Whenever we create {@link BindingProvider}, we use this to configure handlers. 153 */ 154 private @NotNull HandlerConfigurator handlerConfigurator = new HandlerResolverImpl(null); 155 156 private final Class<? extends Service> serviceClass; 157 158 private final WebServiceFeatureList features; 159 160 /** 161 * Name of the service for which this {@link WSServiceDelegate} is created for. 162 */ 163 private final @NotNull QName serviceName; 164 165 /** 166 * Information about SEI, keyed by their interface type. 167 */ 168 // private final Map<Class,SEIPortInfo> seiContext = new HashMap<Class,SEIPortInfo>(); 169 private final Map<QName,SEIPortInfo> seiContext = new HashMap<QName,SEIPortInfo>(); 170 171 // This executor is used for all the async invocations for all proxies 172 // created from this service. But once the proxy is created, then changing 173 // this executor doesn't affect the already created proxies. 174 private volatile Executor executor; 175 176 /** 177 * The WSDL service that this {@link Service} object represents. 178 * <p> 179 * This field is null iff no WSDL is given to {@link Service}. 180 * This fiels can be be null if the service is created without wsdl but later 181 * the epr supplies a wsdl that can be parsed. 182 */ 183 private @Nullable WSDLService wsdlService; 184 185 private final Container container; 186 /** 187 * Multiple {@link ServiceInterceptor}s are aggregated into one. 188 */ 189 /*package*/ final @NotNull ServiceInterceptor serviceInterceptor; 190 private URL wsdlURL; 191 192 public WSServiceDelegate(URL wsdlDocumentLocation, QName serviceName, Class<? extends Service> serviceClass, WebServiceFeature... features) { 193 this(wsdlDocumentLocation, serviceName, serviceClass, new WebServiceFeatureList(features)); 194 } 195 196 protected WSServiceDelegate(URL wsdlDocumentLocation, QName serviceName, Class<? extends Service> serviceClass, WebServiceFeatureList features) { 197 this( 198 wsdlDocumentLocation==null ? null : new StreamSource(wsdlDocumentLocation.toExternalForm()), 199 serviceName,serviceClass, features); 200 wsdlURL = wsdlDocumentLocation; 201 } 202 203 /** 204 * @param serviceClass 205 * Either {@link Service}.class or other generated service-derived classes. 206 */ 207 public WSServiceDelegate(@Nullable Source wsdl, @NotNull QName serviceName, @NotNull final Class<? extends Service> serviceClass, WebServiceFeature... features) { 208 this(wsdl, serviceName, serviceClass, new WebServiceFeatureList(features)); 209 } 210 211 /** 212 * @param serviceClass 213 * Either {@link Service}.class or other generated service-derived classes. 214 */ 215 protected WSServiceDelegate(@Nullable Source wsdl, @NotNull QName serviceName, @NotNull final Class<? extends Service> serviceClass, WebServiceFeatureList features) { 216 this(wsdl, null, serviceName, serviceClass, features); 217 } 218 219 /** 220 * @param serviceClass 221 * Either {@link Service}.class or other generated service-derived classes. 222 */ 223 public WSServiceDelegate(@Nullable Source wsdl, @Nullable WSDLService service, @NotNull QName serviceName, @NotNull final Class<? extends Service> serviceClass, WebServiceFeature... features) { 224 this(wsdl, service, serviceName, serviceClass, new WebServiceFeatureList(features)); 225 } 226 227 /** 228 * @param serviceClass 229 * Either {@link Service}.class or other generated service-derived classes. 230 */ 231 public WSServiceDelegate(@Nullable Source wsdl, @Nullable WSDLService service, @NotNull QName serviceName, @NotNull final Class<? extends Service> serviceClass, WebServiceFeatureList features) { 232 //we cant create a Service without serviceName 233 if (serviceName == null) { 234 throw new WebServiceException(ClientMessages.INVALID_SERVICE_NAME_NULL(null)); 235 } 236 237 this.features = features; 238 239 InitParams initParams = INIT_PARAMS.get(); 240 INIT_PARAMS.set(null); // mark it as consumed 241 if(initParams==null) { 242 initParams = EMPTY_PARAMS; 243 } 244 245 this.serviceName = serviceName; 246 this.serviceClass = serviceClass; 247 Container tContainer = initParams.getContainer()!=null ? initParams.getContainer() : ContainerResolver.getInstance().getContainer(); 248 if (tContainer == Container.NONE) { 249 tContainer = new ClientContainer(); 250 } 251 this.container = tContainer; 252 253 ComponentFeature cf = this.features.get(ComponentFeature.class); 254 if (cf != null) { 255 switch(cf.getTarget()) { 256 case SERVICE: 257 getComponents().add(cf.getComponent()); 258 break; 259 case CONTAINER: 260 this.container.getComponents().add(cf.getComponent()); 261 break; 262 default: 263 throw new IllegalArgumentException(); 264 } 265 } 266 ComponentsFeature csf = this.features.get(ComponentsFeature.class); 267 if (csf != null) { 268 for (ComponentFeature cfi : csf.getComponentFeatures()) { 269 switch(cfi.getTarget()) { 270 case SERVICE: 271 getComponents().add(cfi.getComponent()); 272 break; 273 case CONTAINER: 274 this.container.getComponents().add(cfi.getComponent()); 275 break; 276 default: 277 throw new IllegalArgumentException(); 278 } 279 } 280 } 281 282 // load interceptor 283 ServiceInterceptor interceptor = ServiceInterceptorFactory.load(this, Thread.currentThread().getContextClassLoader()); 284 ServiceInterceptor si = container.getSPI(ServiceInterceptor.class); 285 if (si != null) { 286 interceptor = ServiceInterceptor.aggregate(interceptor, si); 287 } 288 this.serviceInterceptor = interceptor; 289 290 if (service == null) { 291 //if wsdl is null, try and get it from the WebServiceClient.wsdlLocation 292 if(wsdl == null){ 293 if(serviceClass != Service.class){ 294 WebServiceClient wsClient = AccessController.doPrivileged(new PrivilegedAction<WebServiceClient>() { 295 public WebServiceClient run() { 296 return serviceClass.getAnnotation(WebServiceClient.class); 297 } 298 }); 299 String wsdlLocation = wsClient.wsdlLocation(); 300 wsdlLocation = JAXWSUtils.absolutize(JAXWSUtils.getFileOrURLName(wsdlLocation)); 301 wsdl = new StreamSource(wsdlLocation); 302 } 303 } 304 if (wsdl != null) { 305 try { 306 URL url = wsdl.getSystemId()==null ? null : JAXWSUtils.getEncodedURL(wsdl.getSystemId()); 307 WSDLModel model = parseWSDL(url, wsdl, serviceClass); 308 service = model.getService(this.serviceName); 309 if (service == null) 310 throw new WebServiceException( 311 ClientMessages.INVALID_SERVICE_NAME(this.serviceName, 312 buildNameList(model.getServices().keySet()))); 313 // fill in statically known ports 314 for (WSDLPort port : service.getPorts()) 315 ports.put(port.getName(), new PortInfo(this, port)); 316 } catch (MalformedURLException e) { 317 throw new WebServiceException(ClientMessages.INVALID_WSDL_URL(wsdl.getSystemId())); 318 } 319 } 320 } else { 321 // fill in statically known ports 322 for (WSDLPort port : service.getPorts()) 323 ports.put(port.getName(), new PortInfo(this, port)); 324 } 325 this.wsdlService = service; 326 327 if (serviceClass != Service.class) { 328 //if @HandlerChain present, set HandlerResolver on service context 329 HandlerChain handlerChain = 330 AccessController.doPrivileged(new PrivilegedAction<HandlerChain>() { 331 public HandlerChain run() { 332 return serviceClass.getAnnotation(HandlerChain.class); 333 } 334 }); 335 if (handlerChain != null) 336 handlerConfigurator = new AnnotationConfigurator(this); 337 } 338 339 } 340 341 /** 342 * Parses the WSDL and builds {@link com.sun.xml.internal.ws.api.model.wsdl.WSDLModel}. 343 * @param wsdlDocumentLocation 344 * Either this or {@code wsdl} parameter must be given. 345 * Null location means the system won't be able to resolve relative references in the WSDL. 346 */ 347 private WSDLModel parseWSDL(URL wsdlDocumentLocation, Source wsdlSource, Class serviceClass) { 348 try { 349 return RuntimeWSDLParser.parse(wsdlDocumentLocation, wsdlSource, createCatalogResolver(), 350 true, getContainer(), serviceClass, ServiceFinder.find(WSDLParserExtension.class).toArray()); 351 } catch (IOException e) { 352 throw new WebServiceException(e); 353 } catch (XMLStreamException e) { 354 throw new WebServiceException(e); 355 } catch (SAXException e) { 356 throw new WebServiceException(e); 357 } catch (ServiceConfigurationError e) { 358 throw new WebServiceException(e); 359 } 360 } 361 362 protected EntityResolver createCatalogResolver() { 363 return createDefaultCatalogResolver(); 364 } 365 366 public Executor getExecutor() { 367 return executor; 368 } 369 370 public void setExecutor(Executor executor) { 371 this.executor = executor; 372 } 373 374 public HandlerResolver getHandlerResolver() { 375 return handlerConfigurator.getResolver(); 376 } 377 378 /*package*/ final HandlerConfigurator getHandlerConfigurator() { 379 return handlerConfigurator; 380 } 381 382 public void setHandlerResolver(HandlerResolver resolver) { 383 handlerConfigurator = new HandlerResolverImpl(resolver); 384 } 385 386 public <T> T getPort(QName portName, Class<T> portInterface) throws WebServiceException { 387 return getPort(portName, portInterface, EMPTY_FEATURES); 388 } 389 390 public <T> T getPort(QName portName, Class<T> portInterface, WebServiceFeature... features) { 391 if (portName == null || portInterface == null) 392 throw new IllegalArgumentException(); 393 WSDLService tWsdlService = this.wsdlService; 394 if (tWsdlService == null) { 395 // assigning it to local variable and not setting it back to this.wsdlService intentionally 396 // as we don't want to include the service instance with information gathered from sei 397 tWsdlService = getWSDLModelfromSEI(portInterface); 398 //still null? throw error need wsdl metadata to create a proxy 399 if (tWsdlService == null) { 400 throw new WebServiceException(ProviderApiMessages.NO_WSDL_NO_PORT(portInterface.getName())); 401 } 402 403 } 404 WSDLPort portModel = getPortModel(tWsdlService, portName); 405 return getPort(portModel.getEPR(), portName, portInterface, new WebServiceFeatureList(features)); 406 } 407 408 public <T> T getPort(EndpointReference epr, Class<T> portInterface, WebServiceFeature... features) { 409 return getPort(WSEndpointReference.create(epr),portInterface,features); 410 } 411 412 public <T> T getPort(WSEndpointReference wsepr, Class<T> portInterface, WebServiceFeature... features) { 413 //get the portType from SEI, so that it can be used if EPR does n't have endpointName 414 WebServiceFeatureList featureList = new WebServiceFeatureList(features); 415 QName portTypeName = RuntimeModeler.getPortTypeName(portInterface, getMetadadaReader(featureList, portInterface.getClassLoader())); 416 //if port name is not specified in EPR, it will use portTypeName to get it from the WSDL model. 417 QName portName = getPortNameFromEPR(wsepr, portTypeName); 418 return getPort(wsepr,portName,portInterface, featureList); 419 } 420 421 protected <T> T getPort(WSEndpointReference wsepr, QName portName, Class<T> portInterface, 422 WebServiceFeatureList features) { 423 ComponentFeature cf = features.get(ComponentFeature.class); 424 if (cf != null && !Target.STUB.equals(cf.getTarget())) { 425 throw new IllegalArgumentException(); 426 } 427 ComponentsFeature csf = features.get(ComponentsFeature.class); 428 if (csf != null) { 429 for (ComponentFeature cfi : csf.getComponentFeatures()) { 430 if (!Target.STUB.equals(cfi.getTarget())) 431 throw new IllegalArgumentException(); 432 } 433 } 434 features.addAll(this.features); 435 436 SEIPortInfo spi = addSEI(portName, portInterface, features); 437 return createEndpointIFBaseProxy(wsepr,portName,portInterface,features, spi); 438 } 439 440 @Override 441 public <T> T getPort(Class<T> portInterface, WebServiceFeature... features) { 442 //get the portType from SEI 443 QName portTypeName = RuntimeModeler.getPortTypeName(portInterface, getMetadadaReader(new WebServiceFeatureList(features), portInterface.getClassLoader())); 444 WSDLService tmpWsdlService = this.wsdlService; 445 if (tmpWsdlService == null) { 446 // assigning it to local variable and not setting it back to this.wsdlService intentionally 447 // as we don't want to include the service instance with information gathered from sei 448 tmpWsdlService = getWSDLModelfromSEI(portInterface); 449 //still null? throw error need wsdl metadata to create a proxy 450 if(tmpWsdlService == null) { 451 throw new WebServiceException(ProviderApiMessages.NO_WSDL_NO_PORT(portInterface.getName())); 452 } 453 } 454 //get the first port corresponding to the SEI 455 WSDLPort port = tmpWsdlService.getMatchingPort(portTypeName); 456 if (port == null) { 457 throw new WebServiceException(ClientMessages.UNDEFINED_PORT_TYPE(portTypeName)); 458 } 459 QName portName = port.getName(); 460 return getPort(portName, portInterface,features); 461 } 462 463 public <T> T getPort(Class<T> portInterface) throws WebServiceException { 464 return getPort(portInterface, EMPTY_FEATURES); 465 } 466 467 public void addPort(QName portName, String bindingId, String endpointAddress) throws WebServiceException { 468 if (!ports.containsKey(portName)) { 469 BindingID bid = (bindingId == null) ? BindingID.SOAP11_HTTP : BindingID.parse(bindingId); 470 ports.put(portName, 471 new PortInfo(this, (endpointAddress == null) ? null : 472 EndpointAddress.create(endpointAddress), portName, bid)); 473 } else 474 throw new WebServiceException(DispatchMessages.DUPLICATE_PORT(portName.toString())); 475 } 476 477 478 public <T> Dispatch<T> createDispatch(QName portName, Class<T> aClass, Service.Mode mode) throws WebServiceException { 479 return createDispatch(portName, aClass, mode, EMPTY_FEATURES); 480 } 481 482 @Override 483 public <T> Dispatch<T> createDispatch(QName portName, WSEndpointReference wsepr, Class<T> aClass, Service.Mode mode, WebServiceFeature... features) { 484 return createDispatch(portName, wsepr, aClass, mode, new WebServiceFeatureList(features)); 485 } 486 487 public <T> Dispatch<T> createDispatch(QName portName, WSEndpointReference wsepr, Class<T> aClass, Service.Mode mode, WebServiceFeatureList features) { 488 PortInfo port = safeGetPort(portName); 489 490 ComponentFeature cf = features.get(ComponentFeature.class); 491 if (cf != null && !Target.STUB.equals(cf.getTarget())) { 492 throw new IllegalArgumentException(); 493 } 494 ComponentsFeature csf = features.get(ComponentsFeature.class); 495 if (csf != null) { 496 for (ComponentFeature cfi : csf.getComponentFeatures()) { 497 if (!Target.STUB.equals(cfi.getTarget())) 498 throw new IllegalArgumentException(); 499 } 500 } 501 features.addAll(this.features); 502 503 BindingImpl binding = port.createBinding(features, null, null); 504 binding.setMode(mode); 505 Dispatch<T> dispatch = Stubs.createDispatch(port, this, binding, aClass, mode, wsepr); 506 serviceInterceptor.postCreateDispatch((WSBindingProvider) dispatch); 507 return dispatch; 508 } 509 510 public <T> Dispatch<T> createDispatch(QName portName, Class<T> aClass, Service.Mode mode, WebServiceFeature... features) { 511 return createDispatch(portName, aClass, mode, new WebServiceFeatureList(features)); 512 } 513 514 public <T> Dispatch<T> createDispatch(QName portName, Class<T> aClass, Service.Mode mode, WebServiceFeatureList features) { 515 WSEndpointReference wsepr = null; 516 boolean isAddressingEnabled = false; 517 AddressingFeature af = features.get(AddressingFeature.class); 518 if (af == null) { 519 af = this.features.get(AddressingFeature.class); 520 } 521 if (af != null && af.isEnabled()) 522 isAddressingEnabled = true; 523 MemberSubmissionAddressingFeature msa = features.get(MemberSubmissionAddressingFeature.class); 524 if (msa == null) { 525 msa = this.features.get(MemberSubmissionAddressingFeature.class); 526 } 527 if (msa != null && msa.isEnabled()) 528 isAddressingEnabled = true; 529 if(isAddressingEnabled && wsdlService != null && wsdlService.get(portName) != null) { 530 wsepr = wsdlService.get(portName).getEPR(); 531 } 532 return createDispatch(portName, wsepr, aClass, mode, features); 533 } 534 535 public <T> Dispatch<T> createDispatch(EndpointReference endpointReference, Class<T> type, Service.Mode mode, WebServiceFeature... features) { 536 WSEndpointReference wsepr = new WSEndpointReference(endpointReference); 537 QName portName = addPortEpr(wsepr); 538 return createDispatch(portName, wsepr, type, mode, features); 539 } 540 541 /** 542 * Obtains {@link PortInfo} for the given name, with error check. 543 */ 544 public 545 @NotNull 546 PortInfo safeGetPort(QName portName) { 547 PortInfo port = ports.get(portName); 548 if (port == null) { 549 throw new WebServiceException(ClientMessages.INVALID_PORT_NAME(portName, buildNameList(ports.keySet()))); 550 } 551 return port; 552 } 553 554 private StringBuilder buildNameList(Collection<QName> names) { 555 StringBuilder sb = new StringBuilder(); 556 for (QName qn : names) { 557 if (sb.length() > 0) sb.append(','); 558 sb.append(qn); 559 } 560 return sb; 561 } 562 563 public EndpointAddress getEndpointAddress(QName qName) { 564 PortInfo p = ports.get(qName); 565 return p != null ? p.targetEndpoint : null; 566 } 567 568 public Dispatch<Object> createDispatch(QName portName, JAXBContext jaxbContext, Service.Mode mode) throws WebServiceException { 569 return createDispatch(portName, jaxbContext, mode, EMPTY_FEATURES); 570 } 571 572 @Override 573 public Dispatch<Object> createDispatch(QName portName, WSEndpointReference wsepr, JAXBContext jaxbContext, Service.Mode mode, WebServiceFeature... features) { 574 return createDispatch(portName, wsepr, jaxbContext, mode, new WebServiceFeatureList(features)); 575 } 576 577 protected Dispatch<Object> createDispatch(QName portName, WSEndpointReference wsepr, JAXBContext jaxbContext, Service.Mode mode, WebServiceFeatureList features) { 578 PortInfo port = safeGetPort(portName); 579 580 ComponentFeature cf = features.get(ComponentFeature.class); 581 if (cf != null && !Target.STUB.equals(cf.getTarget())) { 582 throw new IllegalArgumentException(); 583 } 584 ComponentsFeature csf = features.get(ComponentsFeature.class); 585 if (csf != null) { 586 for (ComponentFeature cfi : csf.getComponentFeatures()) { 587 if (!Target.STUB.equals(cfi.getTarget())) 588 throw new IllegalArgumentException(); 589 } 590 } 591 features.addAll(this.features); 592 593 BindingImpl binding = port.createBinding(features, null, null); 594 binding.setMode(mode); 595 Dispatch<Object> dispatch = Stubs.createJAXBDispatch( 596 port, binding, jaxbContext, mode,wsepr); 597 serviceInterceptor.postCreateDispatch((WSBindingProvider)dispatch); 598 return dispatch; 599 } 600 601 @Override 602 public @NotNull Container getContainer() { 603 return container; 604 } 605 606 public Dispatch<Object> createDispatch(QName portName, JAXBContext jaxbContext, Service.Mode mode, WebServiceFeature... webServiceFeatures) { 607 return createDispatch(portName, jaxbContext, mode, new WebServiceFeatureList(webServiceFeatures)); 608 } 609 610 protected Dispatch<Object> createDispatch(QName portName, JAXBContext jaxbContext, Service.Mode mode, WebServiceFeatureList features) { 611 WSEndpointReference wsepr = null; 612 boolean isAddressingEnabled = false; 613 AddressingFeature af = features.get(AddressingFeature.class); 614 if (af == null) { 615 af = this.features.get(AddressingFeature.class); 616 } 617 if (af != null && af.isEnabled()) 618 isAddressingEnabled = true; 619 MemberSubmissionAddressingFeature msa = features.get(MemberSubmissionAddressingFeature.class); 620 if (msa == null) { 621 msa = this.features.get(MemberSubmissionAddressingFeature.class); 622 } 623 if (msa != null && msa.isEnabled()) 624 isAddressingEnabled = true; 625 if(isAddressingEnabled && wsdlService != null && wsdlService.get(portName) != null) { 626 wsepr = wsdlService.get(portName).getEPR(); 627 } 628 return createDispatch(portName, wsepr, jaxbContext, mode, features); 629 } 630 631 public Dispatch<Object> createDispatch(EndpointReference endpointReference, JAXBContext context, Service.Mode mode, WebServiceFeature... features) { 632 WSEndpointReference wsepr = new WSEndpointReference(endpointReference); 633 QName portName = addPortEpr(wsepr); 634 return createDispatch(portName, wsepr, context, mode, features); 635 } 636 637 private QName addPortEpr(WSEndpointReference wsepr) { 638 if (wsepr == null) 639 throw new WebServiceException(ProviderApiMessages.NULL_EPR()); 640 QName eprPortName = getPortNameFromEPR(wsepr, null); 641 //add Port, if it does n't exist; 642 // TODO: what if it has different epr address? 643 { 644 PortInfo portInfo = new PortInfo(this, (wsepr.getAddress() == null) ? null : EndpointAddress.create(wsepr.getAddress()), eprPortName, 645 getPortModel(wsdlService, eprPortName).getBinding().getBindingId()); 646 if (!ports.containsKey(eprPortName)) { 647 ports.put(eprPortName, portInfo); 648 } 649 } 650 return eprPortName; 651 } 652 653 /** 654 * 655 * @param wsepr EndpointReference from which portName will be extracted. 656 * If EndpointName ( port name) is null in EPR, then it will try to get if from WSDLModel using portType QName 657 * @param portTypeName 658 * should be null in dispatch case 659 * should be non null in SEI case 660 * @return 661 * port name from EPR after validating various metadat elements. 662 * Also if service instance does n't have wsdl, 663 * then it gets the WSDL metadata from EPR and builds wsdl model. 664 */ 665 private QName getPortNameFromEPR(@NotNull WSEndpointReference wsepr, @Nullable QName portTypeName) { 666 QName portName; 667 WSEndpointReference.Metadata metadata = wsepr.getMetaData(); 668 QName eprServiceName = metadata.getServiceName(); 669 QName eprPortName = metadata.getPortName(); 670 if ((eprServiceName != null ) && !eprServiceName.equals(serviceName)) { 671 throw new WebServiceException("EndpointReference WSDL ServiceName differs from Service Instance WSDL Service QName.\n" 672 + " The two Service QNames must match"); 673 } 674 if (wsdlService == null) { 675 Source eprWsdlSource = metadata.getWsdlSource(); 676 if (eprWsdlSource == null) { 677 throw new WebServiceException(ProviderApiMessages.NULL_WSDL()); 678 } 679 try { 680 WSDLModel eprWsdlMdl = parseWSDL(new URL(wsepr.getAddress()), eprWsdlSource, null); 681 wsdlService = eprWsdlMdl.getService(serviceName); 682 if (wsdlService == null) 683 throw new WebServiceException(ClientMessages.INVALID_SERVICE_NAME(serviceName, 684 buildNameList(eprWsdlMdl.getServices().keySet()))); 685 } catch (MalformedURLException e) { 686 throw new WebServiceException(ClientMessages.INVALID_ADDRESS(wsepr.getAddress())); 687 } 688 } 689 portName = eprPortName; 690 691 if (portName == null && portTypeName != null) { 692 //get the first port corresponding to the SEI 693 WSDLPort port = wsdlService.getMatchingPort(portTypeName); 694 if (port == null) 695 throw new WebServiceException(ClientMessages.UNDEFINED_PORT_TYPE(portTypeName)); 696 portName = port.getName(); 697 } 698 if (portName == null) 699 throw new WebServiceException(ProviderApiMessages.NULL_PORTNAME()); 700 if (wsdlService.get(portName) == null) 701 throw new WebServiceException(ClientMessages.INVALID_EPR_PORT_NAME(portName, buildWsdlPortNames())); 702 703 return portName; 704 705 } 706 707 private <T> T createProxy(final Class<T> portInterface, final InvocationHandler pis) { 708 709 // When creating the proxy, use a ClassLoader that can load classes 710 // from both the interface class and also from this classes 711 // classloader. This is necessary when this code is used in systems 712 // such as OSGi where the class loader for the interface class may 713 // not be able to load internal JAX-WS classes like 714 // "WSBindingProvider", but the class loader for this class may not 715 // be able to load the interface class. 716 final ClassLoader loader = getDelegatingLoader(portInterface.getClassLoader(), 717 WSServiceDelegate.class.getClassLoader()); 718 719 return AccessController.doPrivileged( 720 new PrivilegedAction<T>() { 721 @Override 722 public T run() { 723 Object proxy = Proxy.newProxyInstance(loader, 724 new Class[]{portInterface, WSBindingProvider.class, Closeable.class}, pis); 725 return portInterface.cast(proxy); 726 } 727 }); 728 729 } 730 731 private WSDLService getWSDLModelfromSEI(final Class sei) { 732 WebService ws = AccessController.doPrivileged(new PrivilegedAction<WebService>() { 733 public WebService run() { 734 return (WebService) sei.getAnnotation(WebService.class); 735 } 736 }); 737 if (ws == null || ws.wsdlLocation().equals("")) 738 return null; 739 String wsdlLocation = ws.wsdlLocation(); 740 wsdlLocation = JAXWSUtils.absolutize(JAXWSUtils.getFileOrURLName(wsdlLocation)); 741 Source wsdl = new StreamSource(wsdlLocation); 742 WSDLService service = null; 743 744 try { 745 URL url = wsdl.getSystemId() == null ? null : new URL(wsdl.getSystemId()); 746 WSDLModel model = parseWSDL(url, wsdl, sei); 747 service = model.getService(this.serviceName); 748 if (service == null) 749 throw new WebServiceException( 750 ClientMessages.INVALID_SERVICE_NAME(this.serviceName, 751 buildNameList(model.getServices().keySet()))); 752 } catch (MalformedURLException e) { 753 throw new WebServiceException(ClientMessages.INVALID_WSDL_URL(wsdl.getSystemId())); 754 } 755 return service; 756 } 757 758 public QName getServiceName() { 759 return serviceName; 760 } 761 762 public Class getServiceClass() { 763 return serviceClass; 764 } 765 766 public Iterator<QName> getPorts() throws WebServiceException { 767 // KK: the spec seems to be ambigous about whether 768 // this returns ports that are dynamically added or not. 769 return ports.keySet().iterator(); 770 } 771 772 @Override 773 public URL getWSDLDocumentLocation() { 774 if(wsdlService==null) return null; 775 try { 776 return new URL(wsdlService.getParent().getLocation().getSystemId()); 777 } catch (MalformedURLException e) { 778 throw new AssertionError(e); // impossible 779 } 780 } 781 782 private <T> T createEndpointIFBaseProxy(@Nullable WSEndpointReference epr, QName portName, Class<T> portInterface, 783 WebServiceFeatureList webServiceFeatures, SEIPortInfo eif) { 784 //fail if service doesnt have WSDL 785 if (wsdlService == null) { 786 throw new WebServiceException(ClientMessages.INVALID_SERVICE_NO_WSDL(serviceName)); 787 } 788 789 if (wsdlService.get(portName)==null) { 790 throw new WebServiceException( 791 ClientMessages.INVALID_PORT_NAME(portName,buildWsdlPortNames())); 792 } 793 794 BindingImpl binding = eif.createBinding(webServiceFeatures, portInterface); 795 InvocationHandler pis = getStubHandler(binding, eif, epr); 796 797 T proxy = createProxy(portInterface, pis); 798 799 if (serviceInterceptor != null) { 800 serviceInterceptor.postCreateProxy((WSBindingProvider)proxy, portInterface); 801 } 802 return proxy; 803 } 804 805 protected InvocationHandler getStubHandler(BindingImpl binding, SEIPortInfo eif, @Nullable WSEndpointReference epr) { 806 return new SEIStub(eif, binding, eif.model, epr); 807 } 808 809 /** 810 * Lists up the port names in WSDL. For error diagnostics. 811 */ 812 private StringBuilder buildWsdlPortNames() { 813 Set<QName> wsdlPortNames = new HashSet<QName>(); 814 for (WSDLPort port : wsdlService.getPorts()) { 815 wsdlPortNames.add(port.getName()); 816 } 817 return buildNameList(wsdlPortNames); 818 } 819 820 /** 821 * Obtains a {@link WSDLPortImpl} with error check. 822 * 823 * @return guaranteed to be non-null. 824 */ 825 public @NotNull WSDLPort getPortModel(WSDLService wsdlService, QName portName) { 826 WSDLPort port = wsdlService.get(portName); 827 if (port == null) 828 throw new WebServiceException( 829 ClientMessages.INVALID_PORT_NAME(portName,buildWsdlPortNames())); 830 return port; 831 } 832 833 /** 834 * Contributes to the construction of {@link WSServiceDelegate} by filling in 835 * {@link SEIPortInfo} about a given SEI (linked from the {@link Service}-derived class.) 836 */ 837 //todo: valid port in wsdl 838 private SEIPortInfo addSEI(QName portName, Class portInterface, WebServiceFeatureList features) throws WebServiceException { 839 boolean ownModel = useOwnSEIModel(features); 840 if (ownModel) { 841 // Create a new model and do not cache it 842 return createSEIPortInfo(portName, portInterface, features); 843 } 844 845 SEIPortInfo spi = seiContext.get(portName); 846 if (spi == null) { 847 spi = createSEIPortInfo(portName, portInterface, features); 848 seiContext.put(spi.portName, spi); 849 ports.put(spi.portName, spi); 850 } 851 return spi; 852 } 853 854 public SEIModel buildRuntimeModel(QName serviceName, QName portName, Class portInterface, WSDLPort wsdlPort, WebServiceFeatureList features) { 855 DatabindingFactory fac = DatabindingFactory.newInstance(); 856 DatabindingConfig config = new DatabindingConfig(); 857 config.setContractClass(portInterface); 858 config.getMappingInfo().setServiceName(serviceName); 859 config.setWsdlPort(wsdlPort); 860 config.setFeatures(features); 861 config.setClassLoader(portInterface.getClassLoader()); 862 config.getMappingInfo().setPortName(portName); 863 config.setWsdlURL(wsdlURL); 864 // if ExternalMetadataFeature present, ExternalMetadataReader will be created ... 865 config.setMetadataReader(getMetadadaReader(features, portInterface.getClassLoader())); 866 867 com.sun.xml.internal.ws.db.DatabindingImpl rt = (com.sun.xml.internal.ws.db.DatabindingImpl)fac.createRuntime(config); 868 869 return rt.getModel(); 870 } 871 872 private MetadataReader getMetadadaReader(WebServiceFeatureList features, ClassLoader classLoader) { 873 if (features == null) return null; 874 com.oracle.webservices.internal.api.databinding.ExternalMetadataFeature ef = 875 features.get(com.oracle.webservices.internal.api.databinding.ExternalMetadataFeature.class); 876 // TODO-Miran: would it be necessary to disable secure xml processing? 877 if (ef != null) 878 return ef.getMetadataReader(classLoader, false); 879 return null; 880 } 881 882 private SEIPortInfo createSEIPortInfo(QName portName, Class portInterface, WebServiceFeatureList features) { 883 WSDLPort wsdlPort = getPortModel(wsdlService, portName); 884 SEIModel model = buildRuntimeModel(serviceName, portName, portInterface, wsdlPort, features); 885 886 return new SEIPortInfo(this, portInterface, (SOAPSEIModel) model, wsdlPort); 887 } 888 889 private boolean useOwnSEIModel(WebServiceFeatureList features) { 890 return features.contains(UsesJAXBContextFeature.class); 891 } 892 893 public WSDLService getWsdlService() { 894 return wsdlService; 895 } 896 897 protected static final WebServiceFeature[] EMPTY_FEATURES = new WebServiceFeature[0]; 898 899 private static ClassLoader getDelegatingLoader(ClassLoader loader1, ClassLoader loader2) { 900 if (loader1 == null) return loader2; 901 if (loader2 == null) return loader1; 902 return new DelegatingLoader(loader1, loader2); 903 } 904 905 private static final class DelegatingLoader extends ClassLoader { 906 private final ClassLoader loader; 907 908 @Override 909 public int hashCode() { 910 final int prime = 31; 911 int result = 1; 912 result = prime * result 913 + ((loader == null) ? 0 : loader.hashCode()); 914 result = prime * result 915 + ((getParent() == null) ? 0 : getParent().hashCode()); 916 return result; 917 } 918 919 @Override 920 public boolean equals(Object obj) { 921 if (this == obj) 922 return true; 923 if (obj == null) 924 return false; 925 if (getClass() != obj.getClass()) 926 return false; 927 DelegatingLoader other = (DelegatingLoader) obj; 928 if (loader == null) { 929 if (other.loader != null) 930 return false; 931 } else if (!loader.equals(other.loader)) 932 return false; 933 if (getParent() == null) { 934 if (other.getParent() != null) 935 return false; 936 } else if (!getParent().equals(other.getParent())) 937 return false; 938 return true; 939 } 940 941 DelegatingLoader(ClassLoader loader1, ClassLoader loader2) { 942 super(loader2); 943 this.loader = loader1; 944 } 945 946 protected Class findClass(String name) throws ClassNotFoundException { 947 return loader.loadClass(name); 948 } 949 950 protected URL findResource(String name) { 951 return loader.getResource(name); 952 } 953 } 954 }