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