Tue, 06 Mar 2012 16:09:35 -0800
7150322: Stop using drop source bundles in jaxws
Reviewed-by: darcy, ohrstrom
1 /*
2 * Copyright (c) 1997, 2010, 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.ComponentFeature.Target;
34 import com.sun.xml.internal.ws.api.EndpointAddress;
35 import com.sun.xml.internal.ws.api.WSService;
36 import com.sun.xml.internal.ws.api.addressing.WSEndpointReference;
37 import com.sun.xml.internal.ws.api.client.ServiceInterceptor;
38 import com.sun.xml.internal.ws.api.client.ServiceInterceptorFactory;
39 import com.sun.xml.internal.ws.api.databinding.DatabindingFactory;
40 import com.sun.xml.internal.ws.api.databinding.DatabindingConfig;
41 import com.sun.xml.internal.ws.api.model.SEIModel;
42 import com.sun.xml.internal.ws.api.model.wsdl.WSDLPort;
43 import com.sun.xml.internal.ws.api.model.wsdl.WSDLService;
44 import com.sun.xml.internal.ws.api.pipe.*;
45 import com.sun.xml.internal.ws.api.server.Container;
46 import com.sun.xml.internal.ws.api.server.ContainerResolver;
47 import com.sun.xml.internal.ws.api.wsdl.parser.WSDLParserExtension;
48 import com.sun.xml.internal.ws.binding.BindingImpl;
49 import com.sun.xml.internal.ws.binding.WebServiceFeatureList;
50 import com.sun.xml.internal.ws.client.HandlerConfigurator.AnnotationConfigurator;
51 import com.sun.xml.internal.ws.client.HandlerConfigurator.HandlerResolverImpl;
52 import com.sun.xml.internal.ws.client.sei.SEIStub;
53 import com.sun.xml.internal.ws.developer.MemberSubmissionAddressingFeature;
54 import com.sun.xml.internal.ws.developer.WSBindingProvider;
55 import com.sun.xml.internal.ws.developer.UsesJAXBContextFeature;
56 import com.sun.xml.internal.ws.model.RuntimeModeler;
57 import com.sun.xml.internal.ws.model.SOAPSEIModel;
58 import com.sun.xml.internal.ws.model.wsdl.WSDLModelImpl;
59 import com.sun.xml.internal.ws.model.wsdl.WSDLPortImpl;
60 import com.sun.xml.internal.ws.model.wsdl.WSDLServiceImpl;
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 static com.sun.xml.internal.ws.util.xml.XmlUtil.createDefaultCatalogResolver;
68 import com.sun.xml.internal.ws.wsdl.parser.RuntimeWSDLParser;
70 import org.xml.sax.EntityResolver;
71 import org.xml.sax.SAXException;
73 import javax.jws.HandlerChain;
74 import javax.jws.WebService;
75 import javax.xml.bind.JAXBContext;
76 import javax.xml.namespace.QName;
77 import javax.xml.stream.XMLStreamException;
78 import javax.xml.transform.Source;
79 import javax.xml.transform.stream.StreamSource;
80 import javax.xml.ws.*;
81 import javax.xml.ws.handler.HandlerResolver;
82 import javax.xml.ws.soap.AddressingFeature;
83 import java.io.IOException;
84 import java.lang.reflect.InvocationHandler;
85 import java.lang.reflect.Proxy;
86 import java.net.MalformedURLException;
87 import java.net.URL;
88 import java.security.AccessController;
89 import java.security.PrivilegedAction;
90 import java.util.*;
91 import java.util.concurrent.Executor;
92 import java.util.concurrent.ThreadFactory;
94 /**
95 * <code>Service</code> objects provide the client view of a Web service.
96 *
97 * <p><code>Service</code> acts as a factory of the following:
98 * <ul>
99 * <li>Proxies for a target service endpoint.
100 * <li>Instances of <code>javax.xml.ws.Dispatch</code> for
101 * dynamic message-oriented invocation of a remote
102 * operation.
103 * </li>
104 *
105 * <p>The ports available on a service can be enumerated using the
106 * <code>getPorts</code> method. Alternatively, you can pass a
107 * service endpoint interface to the unary <code>getPort</code> method
108 * and let the runtime select a compatible port.
109 *
110 * <p>Handler chains for all the objects created by a <code>Service</code>
111 * can be set by means of the provided <code>HandlerRegistry</code>.
112 *
113 * <p>An <code>Executor</code> may be set on the service in order
114 * to gain better control over the threads used to dispatch asynchronous
115 * callbacks. For instance, thread pooling with certain parameters
116 * can be enabled by creating a <code>ThreadPoolExecutor</code> and
117 * registering it with the service.
118 *
119 * @author WS Development Team
120 * @see Executor
121 * @since JAX-WS 2.0
122 */
123 public class WSServiceDelegate extends WSService {
124 /**
125 * All ports.
126 * <p>
127 * This includes ports statically known to WSDL, as well as
128 * ones that are dynamically added
129 * through {@link #addPort(QName, String, String)}.
130 * <p>
131 * For statically known ports we'll have {@link SEIPortInfo}.
132 * For dynamically added ones we'll have {@link PortInfo}.
133 */
134 private final Map<QName, PortInfo> ports = new HashMap<QName, PortInfo>();
135 // For monitoring
136 protected Map<QName, PortInfo> getQNameToPortInfoMap() { return ports; }
138 /**
139 * Whenever we create {@link BindingProvider}, we use this to configure handlers.
140 */
141 private @NotNull HandlerConfigurator handlerConfigurator = new HandlerResolverImpl(null);
143 private final Class<? extends Service> serviceClass;
145 private final WebServiceFeatureList features;
147 /**
148 * Name of the service for which this {@link WSServiceDelegate} is created for.
149 */
150 private final @NotNull QName serviceName;
152 /**
153 * Information about SEI, keyed by their interface type.
154 */
155 // private final Map<Class,SEIPortInfo> seiContext = new HashMap<Class,SEIPortInfo>();
156 private final Map<QName,SEIPortInfo> seiContext = new HashMap<QName,SEIPortInfo>();
158 // This executor is used for all the async invocations for all proxies
159 // created from this service. But once the proxy is created, then changing
160 // this executor doesn't affect the already created proxies.
161 private volatile Executor executor;
163 /**
164 * The WSDL service that this {@link Service} object represents.
165 * <p>
166 * This field is null iff no WSDL is given to {@link Service}.
167 * This fiels can be be null if the service is created without wsdl but later
168 * the epr supplies a wsdl that can be parsed.
169 */
170 private @Nullable WSDLServiceImpl wsdlService;
172 private final Container container;
173 /**
174 * Multiple {@link ServiceInterceptor}s are aggregated into one.
175 */
176 /*package*/ final @NotNull ServiceInterceptor serviceInterceptor;
179 public WSServiceDelegate(URL wsdlDocumentLocation, QName serviceName, Class<? extends Service> serviceClass, WebServiceFeature... features) {
180 this(
181 wsdlDocumentLocation==null ? null : new StreamSource(wsdlDocumentLocation.toExternalForm()),
182 serviceName,serviceClass, features);
183 }
185 /**
186 * @param serviceClass
187 * Either {@link Service}.class or other generated service-derived classes.
188 */
189 public WSServiceDelegate(@Nullable Source wsdl, @NotNull QName serviceName, @NotNull final Class<? extends Service> serviceClass, WebServiceFeature... features) {
190 this(wsdl, null, serviceName, serviceClass, features);
191 }
193 /**
194 * @param serviceClass
195 * Either {@link Service}.class or other generated service-derived classes.
196 */
197 public WSServiceDelegate(@Nullable Source wsdl, @Nullable WSDLServiceImpl service, @NotNull QName serviceName, @NotNull final Class<? extends Service> serviceClass, WebServiceFeature... features) {
198 //we cant create a Service without serviceName
199 if (serviceName == null)
200 throw new WebServiceException(ClientMessages.INVALID_SERVICE_NAME_NULL(serviceName));
202 this.features = new WebServiceFeatureList(features);
204 InitParams initParams = INIT_PARAMS.get();
205 INIT_PARAMS.set(null); // mark it as consumed
206 if(initParams==null) initParams = EMPTY_PARAMS;
208 this.serviceName = serviceName;
209 this.serviceClass = serviceClass;
210 Container tContainer = initParams.getContainer()!=null ? initParams.getContainer() : ContainerResolver.getInstance().getContainer();
211 if (tContainer == Container.NONE) {
212 tContainer = new ClientContainer();
213 }
214 this.container = tContainer;
216 ComponentFeature cf = this.features.get(ComponentFeature.class);
217 if (cf != null) {
218 switch(cf.getTarget()) {
219 case SERVICE:
220 getComponents().add(cf.getComponent());
221 break;
222 case CONTAINER:
223 this.container.getComponents().add(cf.getComponent());
224 default:
225 throw new IllegalArgumentException();
226 }
227 }
229 // load interceptor
230 ServiceInterceptor interceptor = ServiceInterceptorFactory.load(this, Thread.currentThread().getContextClassLoader());
231 ServiceInterceptor si = container.getSPI(ServiceInterceptor.class);
232 if (si != null) {
233 interceptor = ServiceInterceptor.aggregate(interceptor, si);
234 }
235 this.serviceInterceptor = interceptor;
237 if (service == null) {
238 //if wsdl is null, try and get it from the WebServiceClient.wsdlLocation
239 if(wsdl == null){
240 if(serviceClass != Service.class){
241 WebServiceClient wsClient = AccessController.doPrivileged(new PrivilegedAction<WebServiceClient>() {
242 public WebServiceClient run() {
243 return serviceClass.getAnnotation(WebServiceClient.class);
244 }
245 });
246 String wsdlLocation = wsClient.wsdlLocation();
247 wsdlLocation = JAXWSUtils.absolutize(JAXWSUtils.getFileOrURLName(wsdlLocation));
248 wsdl = new StreamSource(wsdlLocation);
249 }
250 }
251 if (wsdl != null) {
252 try {
253 URL url = wsdl.getSystemId()==null ? null : JAXWSUtils.getEncodedURL(wsdl.getSystemId());
254 WSDLModelImpl model = parseWSDL(url, wsdl, serviceClass);
255 service = model.getService(this.serviceName);
256 if (service == null)
257 throw new WebServiceException(
258 ClientMessages.INVALID_SERVICE_NAME(this.serviceName,
259 buildNameList(model.getServices().keySet())));
260 // fill in statically known ports
261 for (WSDLPort port : service.getPorts())
262 ports.put(port.getName(), new PortInfo(this, port));
263 } catch (MalformedURLException e) {
264 throw new WebServiceException(ClientMessages.INVALID_WSDL_URL(wsdl.getSystemId()));
265 }
266 }
267 }
268 this.wsdlService = service;
270 if (serviceClass != Service.class) {
271 //if @HandlerChain present, set HandlerResolver on service context
272 HandlerChain handlerChain =
273 AccessController.doPrivileged(new PrivilegedAction<HandlerChain>() {
274 public HandlerChain run() {
275 return serviceClass.getAnnotation(HandlerChain.class);
276 }
277 });
278 if (handlerChain != null)
279 handlerConfigurator = new AnnotationConfigurator(this);
280 }
282 }
284 /**
285 * Parses the WSDL and builds {@link com.sun.xml.internal.ws.api.model.wsdl.WSDLModel}.
286 * @param wsdlDocumentLocation
287 * Either this or <tt>wsdl</tt> parameter must be given.
288 * Null location means the system won't be able to resolve relative references in the WSDL,
289 */
290 private WSDLModelImpl parseWSDL(URL wsdlDocumentLocation, Source wsdlSource, Class serviceClass) {
291 try {
292 return RuntimeWSDLParser.parse(wsdlDocumentLocation, wsdlSource, createCatalogResolver(),
293 true, getContainer(), serviceClass, ServiceFinder.find(WSDLParserExtension.class).toArray());
294 } catch (IOException e) {
295 throw new WebServiceException(e);
296 } catch (XMLStreamException e) {
297 throw new WebServiceException(e);
298 } catch (SAXException e) {
299 throw new WebServiceException(e);
300 } catch (ServiceConfigurationError e) {
301 throw new WebServiceException(e);
302 }
303 }
305 protected EntityResolver createCatalogResolver() {
306 return createDefaultCatalogResolver();
307 }
309 public Executor getExecutor() {
310 return executor;
311 }
313 public void setExecutor(Executor executor) {
314 this.executor = executor;
315 }
317 public HandlerResolver getHandlerResolver() {
318 return handlerConfigurator.getResolver();
319 }
321 /*package*/ final HandlerConfigurator getHandlerConfigurator() {
322 return handlerConfigurator;
323 }
325 public void setHandlerResolver(HandlerResolver resolver) {
326 handlerConfigurator = new HandlerResolverImpl(resolver);
327 }
329 public <T> T getPort(QName portName, Class<T> portInterface) throws WebServiceException {
330 return getPort(portName, portInterface, EMPTY_FEATURES);
331 }
333 public <T> T getPort(QName portName, Class<T> portInterface, WebServiceFeature... features) {
334 if (portName == null || portInterface == null)
335 throw new IllegalArgumentException();
336 WSDLServiceImpl tWsdlService = this.wsdlService;
337 if (tWsdlService == null) {
338 // assigning it to local variable and not setting it back to this.wsdlService intentionally
339 // as we don't want to include the service instance with information gathered from sei
340 tWsdlService = getWSDLModelfromSEI(portInterface);
341 //still null? throw error need wsdl metadata to create a proxy
342 if (tWsdlService == null) {
343 throw new WebServiceException(ProviderApiMessages.NO_WSDL_NO_PORT(portInterface.getName()));
344 }
346 }
347 WSDLPortImpl portModel = getPortModel(tWsdlService, portName);
348 return getPort(portModel.getEPR(), portName, portInterface, new WebServiceFeatureList(features));
349 }
351 public <T> T getPort(EndpointReference epr, Class<T> portInterface, WebServiceFeature... features) {
352 return getPort(WSEndpointReference.create(epr),portInterface,features);
353 }
355 public <T> T getPort(WSEndpointReference wsepr, Class<T> portInterface, WebServiceFeature... features) {
356 //get the portType from SEI, so that it can be used if EPR does n't have endpointName
357 QName portTypeName = RuntimeModeler.getPortTypeName(portInterface);
358 //if port name is not specified in EPR, it will use portTypeName to get it from the WSDL model.
359 QName portName = getPortNameFromEPR(wsepr, portTypeName);
360 return getPort(wsepr,portName,portInterface,new WebServiceFeatureList(features));
361 }
363 protected <T> T getPort(WSEndpointReference wsepr, QName portName, Class<T> portInterface,
364 WebServiceFeatureList features) {
365 ComponentFeature cf = features.get(ComponentFeature.class);
366 if (cf != null && !Target.STUB.equals(cf.getTarget())) {
367 throw new IllegalArgumentException();
368 }
369 features.addAll(this.features);
371 SEIPortInfo spi = addSEI(portName, portInterface, features);
372 return createEndpointIFBaseProxy(wsepr,portName,portInterface,features, spi);
373 }
375 public <T> T getPort(Class<T> portInterface, WebServiceFeature... features) {
376 //get the portType from SEI
377 QName portTypeName = RuntimeModeler.getPortTypeName(portInterface);
378 WSDLServiceImpl wsdlService = this.wsdlService;
379 if(wsdlService == null) {
380 // assigning it to local variable and not setting it back to this.wsdlService intentionally
381 // as we don't want to include the service instance with information gathered from sei
382 wsdlService = getWSDLModelfromSEI(portInterface);
383 //still null? throw error need wsdl metadata to create a proxy
384 if(wsdlService == null) {
385 throw new WebServiceException(ProviderApiMessages.NO_WSDL_NO_PORT(portInterface.getName()));
386 }
387 }
388 //get the first port corresponding to the SEI
389 WSDLPortImpl port = wsdlService.getMatchingPort(portTypeName);
390 if (port == null)
391 throw new WebServiceException(ClientMessages.UNDEFINED_PORT_TYPE(portTypeName));
392 QName portName = port.getName();
393 return getPort(portName, portInterface,features);
394 }
396 public <T> T getPort(Class<T> portInterface) throws WebServiceException {
397 return getPort(portInterface, EMPTY_FEATURES);
398 }
400 public void addPort(QName portName, String bindingId, String endpointAddress) throws WebServiceException {
401 if (!ports.containsKey(portName)) {
402 BindingID bid = (bindingId == null) ? BindingID.SOAP11_HTTP : BindingID.parse(bindingId);
403 ports.put(portName,
404 new PortInfo(this, (endpointAddress == null) ? null :
405 EndpointAddress.create(endpointAddress), portName, bid));
406 } else
407 throw new WebServiceException(DispatchMessages.DUPLICATE_PORT(portName.toString()));
408 }
411 public <T> Dispatch<T> createDispatch(QName portName, Class<T> aClass, Service.Mode mode) throws WebServiceException {
412 return createDispatch(portName, aClass, mode, EMPTY_FEATURES);
413 }
415 @Override
416 public <T> Dispatch<T> createDispatch(QName portName, WSEndpointReference wsepr, Class<T> aClass, Service.Mode mode, WebServiceFeature... features) {
417 return createDispatch(portName, wsepr, aClass, mode, new WebServiceFeatureList(features));
418 }
420 public <T> Dispatch<T> createDispatch(QName portName, WSEndpointReference wsepr, Class<T> aClass, Service.Mode mode, WebServiceFeatureList features) {
421 PortInfo port = safeGetPort(portName);
423 ComponentFeature cf = features.get(ComponentFeature.class);
424 if (cf != null && !Target.STUB.equals(cf.getTarget())) {
425 throw new IllegalArgumentException();
426 }
427 features.addAll(this.features);
429 BindingImpl binding = port.createBinding(features, null, null);
430 binding.setMode(mode);
431 Dispatch<T> dispatch = Stubs.createDispatch(port, this, binding, aClass, mode, wsepr);
432 serviceInterceptor.postCreateDispatch((WSBindingProvider) dispatch);
433 return dispatch;
434 }
436 public <T> Dispatch<T> createDispatch(QName portName, Class<T> aClass, Service.Mode mode, WebServiceFeature... features) {
437 return createDispatch(portName, aClass, mode, new WebServiceFeatureList(features));
438 }
440 public <T> Dispatch<T> createDispatch(QName portName, Class<T> aClass, Service.Mode mode, WebServiceFeatureList features) {
441 WSEndpointReference wsepr = null;
442 boolean isAddressingEnabled = false;
443 AddressingFeature af = features.get(AddressingFeature.class);
444 if (af == null) {
445 af = this.features.get(AddressingFeature.class);
446 }
447 if (af != null && af.isEnabled())
448 isAddressingEnabled = true;
449 MemberSubmissionAddressingFeature msa = features.get(MemberSubmissionAddressingFeature.class);
450 if (msa == null) {
451 msa = this.features.get(MemberSubmissionAddressingFeature.class);
452 }
453 if (msa != null && msa.isEnabled())
454 isAddressingEnabled = true;
455 if(isAddressingEnabled && wsdlService != null && wsdlService.get(portName) != null) {
456 wsepr = wsdlService.get(portName).getEPR();
457 }
458 return createDispatch(portName, wsepr, aClass, mode, features);
459 }
461 public <T> Dispatch<T> createDispatch(EndpointReference endpointReference, Class<T> type, Service.Mode mode, WebServiceFeature... features) {
462 WSEndpointReference wsepr = new WSEndpointReference(endpointReference);
463 QName portName = addPortEpr(wsepr);
464 return createDispatch(portName, wsepr, type, mode, features);
465 }
467 /**
468 * Obtains {@link PortInfo} for the given name, with error check.
469 */
470 public
471 @NotNull
472 PortInfo safeGetPort(QName portName) {
473 PortInfo port = ports.get(portName);
474 if (port == null) {
475 throw new WebServiceException(ClientMessages.INVALID_PORT_NAME(portName, buildNameList(ports.keySet())));
476 }
477 return port;
478 }
480 private StringBuilder buildNameList(Collection<QName> names) {
481 StringBuilder sb = new StringBuilder();
482 for (QName qn : names) {
483 if (sb.length() > 0) sb.append(',');
484 sb.append(qn);
485 }
486 return sb;
487 }
489 public EndpointAddress getEndpointAddress(QName qName) {
490 PortInfo p = ports.get(qName);
491 return p != null ? p.targetEndpoint : null;
492 }
494 public Dispatch<Object> createDispatch(QName portName, JAXBContext jaxbContext, Service.Mode mode) throws WebServiceException {
495 return createDispatch(portName, jaxbContext, mode, EMPTY_FEATURES);
496 }
498 @Override
499 public Dispatch<Object> createDispatch(QName portName, WSEndpointReference wsepr, JAXBContext jaxbContext, Service.Mode mode, WebServiceFeature... features) {
500 return createDispatch(portName, wsepr, jaxbContext, mode, new WebServiceFeatureList(features));
501 }
503 protected Dispatch<Object> createDispatch(QName portName, WSEndpointReference wsepr, JAXBContext jaxbContext, Service.Mode mode, WebServiceFeatureList features) {
504 PortInfo port = safeGetPort(portName);
506 ComponentFeature cf = features.get(ComponentFeature.class);
507 if (cf != null && !Target.STUB.equals(cf.getTarget())) {
508 throw new IllegalArgumentException();
509 }
510 features.addAll(this.features);
512 BindingImpl binding = port.createBinding(features, null, null);
513 binding.setMode(mode);
514 Dispatch<Object> dispatch = Stubs.createJAXBDispatch(
515 port, binding, jaxbContext, mode,wsepr);
516 serviceInterceptor.postCreateDispatch((WSBindingProvider)dispatch);
517 return dispatch;
518 }
520 @Override
521 public @NotNull Container getContainer() {
522 return container;
523 }
525 public Dispatch<Object> createDispatch(QName portName, JAXBContext jaxbContext, Service.Mode mode, WebServiceFeature... webServiceFeatures) {
526 return createDispatch(portName, jaxbContext, mode, new WebServiceFeatureList(webServiceFeatures));
527 }
529 protected Dispatch<Object> createDispatch(QName portName, JAXBContext jaxbContext, Service.Mode mode, WebServiceFeatureList features) {
530 WSEndpointReference wsepr = null;
531 boolean isAddressingEnabled = false;
532 AddressingFeature af = features.get(AddressingFeature.class);
533 if (af == null) {
534 af = this.features.get(AddressingFeature.class);
535 }
536 if (af != null && af.isEnabled())
537 isAddressingEnabled = true;
538 MemberSubmissionAddressingFeature msa = features.get(MemberSubmissionAddressingFeature.class);
539 if (msa == null) {
540 msa = this.features.get(MemberSubmissionAddressingFeature.class);
541 }
542 if (msa != null && msa.isEnabled())
543 isAddressingEnabled = true;
544 if(isAddressingEnabled && wsdlService != null && wsdlService.get(portName) != null) {
545 wsepr = wsdlService.get(portName).getEPR();
546 }
547 return createDispatch(portName, wsepr, jaxbContext, mode, features);
548 }
550 public Dispatch<Object> createDispatch(EndpointReference endpointReference, JAXBContext context, Service.Mode mode, WebServiceFeature... features) {
551 WSEndpointReference wsepr = new WSEndpointReference(endpointReference);
552 QName portName = addPortEpr(wsepr);
553 return createDispatch(portName, wsepr, context, mode, features);
554 }
556 private QName addPortEpr(WSEndpointReference wsepr) {
557 if (wsepr == null)
558 throw new WebServiceException(ProviderApiMessages.NULL_EPR());
559 QName eprPortName = getPortNameFromEPR(wsepr, null);
560 //add Port, if it does n't exist;
561 // TODO: what if it has different epr address?
562 {
563 PortInfo portInfo = new PortInfo(this, (wsepr.getAddress() == null) ? null : EndpointAddress.create(wsepr.getAddress()), eprPortName,
564 getPortModel(wsdlService, eprPortName).getBinding().getBindingId());
565 if (!ports.containsKey(eprPortName)) {
566 ports.put(eprPortName, portInfo);
567 }
568 }
569 return eprPortName;
570 }
572 /**
573 *
574 * @param wsepr EndpointReference from which portName will be extracted.
575 * If EndpointName ( port name) is null in EPR, then it will try to get if from WSDLModel using portType QName
576 * @param portTypeName
577 * should be null in dispatch case
578 * should be non null in SEI case
579 * @return
580 * port name from EPR after validating various metadat elements.
581 * Also if service instance does n't have wsdl,
582 * then it gets the WSDL metadata from EPR and builds wsdl model.
583 */
584 private QName getPortNameFromEPR(@NotNull WSEndpointReference wsepr, @Nullable QName portTypeName) {
585 QName portName;
586 WSEndpointReference.Metadata metadata = wsepr.getMetaData();
587 QName eprServiceName = metadata.getServiceName();
588 QName eprPortName = metadata.getPortName();
589 if ((eprServiceName != null ) && !eprServiceName.equals(serviceName)) {
590 throw new WebServiceException("EndpointReference WSDL ServiceName differs from Service Instance WSDL Service QName.\n"
591 + " The two Service QNames must match");
592 }
593 if (wsdlService == null) {
594 Source eprWsdlSource = metadata.getWsdlSource();
595 if (eprWsdlSource == null) {
596 throw new WebServiceException(ProviderApiMessages.NULL_WSDL());
597 }
598 try {
599 WSDLModelImpl eprWsdlMdl = parseWSDL(new URL(wsepr.getAddress()), eprWsdlSource, null);
600 wsdlService = eprWsdlMdl.getService(serviceName);
601 if (wsdlService == null)
602 throw new WebServiceException(ClientMessages.INVALID_SERVICE_NAME(serviceName,
603 buildNameList(eprWsdlMdl.getServices().keySet())));
604 } catch (MalformedURLException e) {
605 throw new WebServiceException(ClientMessages.INVALID_ADDRESS(wsepr.getAddress()));
606 }
607 }
608 portName = eprPortName;
610 if (portName == null && portTypeName != null) {
611 //get the first port corresponding to the SEI
612 WSDLPortImpl port = wsdlService.getMatchingPort(portTypeName);
613 if (port == null)
614 throw new WebServiceException(ClientMessages.UNDEFINED_PORT_TYPE(portTypeName));
615 portName = port.getName();
616 }
617 if (portName == null)
618 throw new WebServiceException(ProviderApiMessages.NULL_PORTNAME());
619 if (wsdlService.get(portName) == null)
620 throw new WebServiceException(ClientMessages.INVALID_EPR_PORT_NAME(portName, buildWsdlPortNames()));
622 return portName;
624 }
626 private WSDLServiceImpl getWSDLModelfromSEI(final Class sei) {
627 WebService ws = AccessController.doPrivileged(new PrivilegedAction<WebService>() {
628 public WebService run() {
629 return (WebService) sei.getAnnotation(WebService.class);
630 }
631 });
632 if (ws == null || ws.wsdlLocation().equals(""))
633 return null;
634 String wsdlLocation = ws.wsdlLocation();
635 wsdlLocation = JAXWSUtils.absolutize(JAXWSUtils.getFileOrURLName(wsdlLocation));
636 Source wsdl = new StreamSource(wsdlLocation);
637 WSDLServiceImpl service = null;
639 try {
640 URL url = wsdl.getSystemId() == null ? null : new URL(wsdl.getSystemId());
641 WSDLModelImpl model = parseWSDL(url, wsdl, sei);
642 service = model.getService(this.serviceName);
643 if (service == null)
644 throw new WebServiceException(
645 ClientMessages.INVALID_SERVICE_NAME(this.serviceName,
646 buildNameList(model.getServices().keySet())));
647 } catch (MalformedURLException e) {
648 throw new WebServiceException(ClientMessages.INVALID_WSDL_URL(wsdl.getSystemId()));
649 }
650 return service;
651 }
653 public QName getServiceName() {
654 return serviceName;
655 }
657 public Class getServiceClass() {
658 return serviceClass;
659 }
661 public Iterator<QName> getPorts() throws WebServiceException {
662 // KK: the spec seems to be ambigous about whether
663 // this returns ports that are dynamically added or not.
664 return ports.keySet().iterator();
665 }
667 public URL getWSDLDocumentLocation() {
668 if(wsdlService==null) return null;
669 try {
670 return new URL(wsdlService.getParent().getLocation().getSystemId());
671 } catch (MalformedURLException e) {
672 throw new AssertionError(e); // impossible
673 }
674 }
676 private <T> T createEndpointIFBaseProxy(@Nullable WSEndpointReference epr,QName portName, Class<T> portInterface,
677 WebServiceFeatureList webServiceFeatures, SEIPortInfo eif) {
678 //fail if service doesnt have WSDL
679 if (wsdlService == null)
680 throw new WebServiceException(ClientMessages.INVALID_SERVICE_NO_WSDL(serviceName));
682 if (wsdlService.get(portName)==null) {
683 throw new WebServiceException(
684 ClientMessages.INVALID_PORT_NAME(portName,buildWsdlPortNames()));
685 }
687 BindingImpl binding = eif.createBinding(webServiceFeatures,portInterface);
688 InvocationHandler pis = getStubHandler(binding, eif, epr);
690 // When creating the proxy, use a ClassLoader that can load classes
691 // from both the interface class and also from this classes
692 // classloader. This is necessary when this code is used in systems
693 // such as OSGi where the class loader for the interface class may
694 // not be able to load internal JAX-WS classes like
695 // "WSBindingProvider", but the class loader for this class may not
696 // be able to load the interface class.
697 ClassLoader loader =
698 getDelegatingLoader(portInterface.getClassLoader(),
699 WSServiceDelegate.class.getClassLoader());
700 T proxy = portInterface.cast(Proxy.newProxyInstance(loader,
701 new Class[]{portInterface, WSBindingProvider.class, Closeable.class}, pis));
702 if (serviceInterceptor != null) {
703 serviceInterceptor.postCreateProxy((WSBindingProvider)proxy, portInterface);
704 }
705 return proxy;
706 }
708 protected InvocationHandler getStubHandler(BindingImpl binding, SEIPortInfo eif, @Nullable WSEndpointReference epr) {
709 SEIPortInfo spi = (SEIPortInfo) eif;
710 return new SEIStub(eif, binding, eif.model, epr);
711 }
713 /**
714 * Lists up the port names in WSDL. For error diagnostics.
715 */
716 private StringBuilder buildWsdlPortNames() {
717 Set<QName> wsdlPortNames = new HashSet<QName>();
718 for (WSDLPortImpl port : wsdlService.getPorts())
719 wsdlPortNames.add(port.getName());
720 return buildNameList(wsdlPortNames);
721 }
723 /**
724 * Obtains a {@link WSDLPortImpl} with error check.
725 *
726 * @return guaranteed to be non-null.
727 */
728 public @NotNull WSDLPortImpl getPortModel(WSDLServiceImpl wsdlService, QName portName) {
729 WSDLPortImpl port = wsdlService.get(portName);
730 if (port == null)
731 throw new WebServiceException(
732 ClientMessages.INVALID_PORT_NAME(portName,buildWsdlPortNames()));
733 return port;
734 }
736 /**
737 * Contributes to the construction of {@link WSServiceDelegate} by filling in
738 * {@link SEIPortInfo} about a given SEI (linked from the {@link Service}-derived class.)
739 */
740 //todo: valid port in wsdl
741 private SEIPortInfo addSEI(QName portName, Class portInterface, WebServiceFeatureList features) throws WebServiceException {
742 boolean ownModel = useOwnSEIModel(features);
743 if (ownModel) {
744 // Create a new model and do not cache it
745 return createSEIPortInfo(portName, portInterface, features);
746 }
748 SEIPortInfo spi = seiContext.get(portName);
749 if (spi == null) {
750 spi = createSEIPortInfo(portName, portInterface, features);
751 seiContext.put(spi.portName, spi);
752 ports.put(spi.portName, spi);
753 }
754 return spi;
755 }
757 public SEIModel buildRuntimeModel(QName serviceName, QName portName, Class portInterface, WSDLPort wsdlPort, WebServiceFeatureList features) {
758 DatabindingFactory fac = DatabindingFactory.newInstance();
759 DatabindingConfig config = new DatabindingConfig();
760 config.setContractClass(portInterface);
761 config.getMappingInfo().setServiceName(serviceName);
762 config.setWsdlPort(wsdlPort);
763 config.setFeatures(features);
764 config.setClassLoader(portInterface.getClassLoader());
765 config.getMappingInfo().setPortName(portName);
767 com.sun.xml.internal.ws.db.DatabindingImpl rt = (com.sun.xml.internal.ws.db.DatabindingImpl)fac.createRuntime(config);
769 return rt.getModel();
770 }
772 private SEIPortInfo createSEIPortInfo(QName portName, Class portInterface, WebServiceFeatureList features) {
773 WSDLPortImpl wsdlPort = getPortModel(wsdlService, portName);
774 SEIModel model = buildRuntimeModel(serviceName, portName, portInterface, wsdlPort, features);
776 return new SEIPortInfo(this, portInterface, (SOAPSEIModel) model, wsdlPort);
777 }
779 private boolean useOwnSEIModel(WebServiceFeatureList features) {
780 return features.contains(UsesJAXBContextFeature.class);
781 }
783 public WSDLServiceImpl getWsdlService() {
784 return wsdlService;
785 }
787 class DaemonThreadFactory implements ThreadFactory {
788 public Thread newThread(Runnable r) {
789 Thread daemonThread = new Thread(r);
790 daemonThread.setDaemon(Boolean.TRUE);
791 return daemonThread;
792 }
793 }
795 protected static final WebServiceFeature[] EMPTY_FEATURES = new WebServiceFeature[0];
797 private static ClassLoader getDelegatingLoader(ClassLoader loader1, ClassLoader loader2) {
798 if (loader1 == null) return loader2;
799 if (loader2 == null) return loader1;
800 return new DelegatingLoader(loader1, loader2);
801 }
803 private static final class DelegatingLoader
804 extends ClassLoader
805 {
806 private final ClassLoader loader;
808 DelegatingLoader(ClassLoader loader1, ClassLoader loader2)
809 {
810 super(loader2);
811 this.loader = loader1;
812 }
814 protected Class findClass(String name)
815 throws ClassNotFoundException
816 {
817 return loader.loadClass(name);
818 }
820 protected URL findResource(String name)
821 {
822 return loader.getResource(name);
823 }
824 }
825 }