001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common Development
008: * and Distribution License("CDDL") (collectively, the "License"). You
009: * may not use this file except in compliance with the License. You can obtain
010: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
011: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
012: * language governing permissions and limitations under the License.
013: *
014: * When distributing the software, include this License Header Notice in each
015: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
016: * Sun designates this particular file as subject to the "Classpath" exception
017: * as provided by Sun in the GPL Version 2 section of the License file that
018: * accompanied this code. If applicable, add the following below the License
019: * Header, with the fields enclosed by brackets [] replaced by your own
020: * identifying information: "Portions Copyrighted [year]
021: * [name of copyright owner]"
022: *
023: * Contributor(s):
024: *
025: * If you wish your version of this file to be governed by only the CDDL or
026: * only the GPL Version 2, indicate your decision by adding "[Contributor]
027: * elects to include this software in this distribution under the [CDDL or GPL
028: * Version 2] license." If you don't indicate a single choice of license, a
029: * recipient has the option to distribute your version of this file under
030: * either the CDDL, the GPL Version 2 or to extend the choice of license to
031: * its licensees as provided above. However, if you add GPL Version 2 code
032: * and therefore, elected the GPL Version 2 license, then the option applies
033: * only if the new code is made subject to such option by the copyright
034: * holder.
035: */
036:
037: package com.sun.xml.ws.client;
038:
039: import com.sun.istack.NotNull;
040: import com.sun.istack.Nullable;
041: import com.sun.xml.ws.Closeable;
042: import com.sun.xml.ws.api.BindingID;
043: import com.sun.xml.ws.api.EndpointAddress;
044: import com.sun.xml.ws.api.WSBinding;
045: import com.sun.xml.ws.api.WSService;
046: import com.sun.xml.ws.api.addressing.WSEndpointReference;
047: import com.sun.xml.ws.api.client.ServiceInterceptor;
048: import com.sun.xml.ws.api.client.ServiceInterceptorFactory;
049: import com.sun.xml.ws.api.model.SEIModel;
050: import com.sun.xml.ws.api.model.wsdl.WSDLModel;
051: import com.sun.xml.ws.api.pipe.*;
052: import com.sun.xml.ws.api.server.Container;
053: import com.sun.xml.ws.api.server.ContainerResolver;
054: import com.sun.xml.ws.api.wsdl.parser.WSDLParserExtension;
055: import com.sun.xml.ws.binding.BindingImpl;
056: import com.sun.xml.ws.binding.WebServiceFeatureList;
057: import com.sun.xml.ws.client.HandlerConfigurator.AnnotationConfigurator;
058: import com.sun.xml.ws.client.HandlerConfigurator.HandlerResolverImpl;
059: import com.sun.xml.ws.client.sei.SEIStub;
060: import com.sun.xml.ws.developer.WSBindingProvider;
061: import com.sun.xml.ws.model.AbstractSEIModelImpl;
062: import com.sun.xml.ws.model.RuntimeModeler;
063: import com.sun.xml.ws.model.SOAPSEIModel;
064: import com.sun.xml.ws.model.wsdl.WSDLModelImpl;
065: import com.sun.xml.ws.model.wsdl.WSDLPortImpl;
066: import com.sun.xml.ws.model.wsdl.WSDLServiceImpl;
067: import com.sun.xml.ws.resources.ClientMessages;
068: import com.sun.xml.ws.resources.DispatchMessages;
069: import com.sun.xml.ws.resources.ProviderApiMessages;
070: import com.sun.xml.ws.util.JAXWSUtils;
071: import com.sun.xml.ws.util.ServiceConfigurationError;
072: import com.sun.xml.ws.util.ServiceFinder;
073: import static com.sun.xml.ws.util.xml.XmlUtil.createDefaultCatalogResolver;
074: import com.sun.xml.ws.wsdl.parser.RuntimeWSDLParser;
075: import org.xml.sax.SAXException;
076:
077: import javax.jws.HandlerChain;
078: import javax.xml.bind.JAXBContext;
079: import javax.xml.namespace.QName;
080: import javax.xml.stream.XMLStreamException;
081: import javax.xml.transform.Source;
082: import javax.xml.transform.stream.StreamSource;
083: import javax.xml.ws.*;
084: import javax.xml.ws.handler.HandlerResolver;
085: import javax.xml.ws.soap.AddressingFeature;
086: import java.io.IOException;
087: import java.lang.reflect.Proxy;
088: import java.net.MalformedURLException;
089: import java.net.URL;
090: import java.security.AccessController;
091: import java.security.PrivilegedAction;
092: import java.util.*;
093: import java.util.concurrent.Executor;
094: import java.util.concurrent.Executors;
095: import java.util.concurrent.ThreadFactory;
096:
097: /**
098: * <code>Service</code> objects provide the client view of a Web service.
099: *
100: * <p><code>Service</code> acts as a factory of the following:
101: * <ul>
102: * <li>Proxies for a target service endpoint.
103: * <li>Instances of <code>javax.xml.ws.Dispatch</code> for
104: * dynamic message-oriented invocation of a remote
105: * operation.
106: * </li>
107: *
108: * <p>The ports available on a service can be enumerated using the
109: * <code>getPorts</code> method. Alternatively, you can pass a
110: * service endpoint interface to the unary <code>getPort</code> method
111: * and let the runtime select a compatible port.
112: *
113: * <p>Handler chains for all the objects created by a <code>Service</code>
114: * can be set by means of the provided <code>HandlerRegistry</code>.
115: *
116: * <p>An <code>Executor</code> may be set on the service in order
117: * to gain better control over the threads used to dispatch asynchronous
118: * callbacks. For instance, thread pooling with certain parameters
119: * can be enabled by creating a <code>ThreadPoolExecutor</code> and
120: * registering it with the service.
121: *
122: * @author WS Development Team
123: * @see Executor
124: * @since JAX-WS 2.0
125: */
126: public class WSServiceDelegate extends WSService {
127: /**
128: * All ports.
129: * <p>
130: * This includes ports statically known to WSDL, as well as
131: * ones that are dynamically added
132: * through {@link #addPort(QName, String, String)}.
133: * <p>
134: * For statically known ports we'll have {@link SEIPortInfo}.
135: * For dynamically added ones we'll have {@link PortInfo}.
136: */
137: private final Map<QName, PortInfo> ports = new HashMap<QName, PortInfo>();
138:
139: /**
140: * Whenever we create {@link BindingProvider}, we use this to configure handlers.
141: */
142: private @NotNull
143: HandlerConfigurator handlerConfigurator = new HandlerResolverImpl(
144: null);
145:
146: private final Class<? extends Service> serviceClass;
147:
148: /**
149: * Name of the service for which this {@link WSServiceDelegate} is created for.
150: */
151: private final @NotNull
152: QName serviceName;
153:
154: /**
155: * Information about SEI, keyed by their interface type.
156: */
157: // private final Map<Class,SEIPortInfo> seiContext = new HashMap<Class,SEIPortInfo>();
158: private final Map<QName, SEIPortInfo> seiContext = new HashMap<QName, SEIPortInfo>();
159: private Executor executor;
160:
161: /**
162: * The WSDL service that this {@link Service} object represents.
163: * <p>
164: * This field is null iff no WSDL is given to {@link Service}.
165: * This fiels can be be null if the service is created without wsdl but later
166: * the epr supplies a wsdl that can be parsed.
167: */
168: private @Nullable
169: WSDLServiceImpl wsdlService;
170:
171: private final Container container;
172: /**
173: * Multiple {@link ServiceInterceptor}s are aggregated into one.
174: */
175: /*package*/final @NotNull
176: ServiceInterceptor serviceInterceptor;
177:
178: public WSServiceDelegate(URL wsdlDocumentLocation,
179: QName serviceName, Class<? extends Service> serviceClass) {
180: this (wsdlDocumentLocation == null ? null : new StreamSource(
181: wsdlDocumentLocation.toExternalForm()), serviceName,
182: serviceClass);
183: }
184:
185: /**
186: * @param serviceClass
187: * Either {@link Service}.class or other generated service-derived classes.
188: */
189: public WSServiceDelegate(@Nullable
190: Source wsdl, @NotNull
191: QName serviceName, @NotNull
192: final Class<? extends Service> serviceClass) {
193: //we cant create a Service without serviceName
194: if (serviceName == null)
195: throw new WebServiceException(ClientMessages
196: .INVALID_SERVICE_NAME_NULL(serviceName));
197:
198: InitParams initParams = INIT_PARAMS.get();
199: INIT_PARAMS.set(null); // mark it as consumed
200: if (initParams == null)
201: initParams = EMPTY_PARAMS;
202:
203: this .serviceName = serviceName;
204: this .serviceClass = serviceClass;
205: this .container = initParams.getContainer() != null ? initParams
206: .getContainer() : ContainerResolver.getInstance()
207: .getContainer();
208:
209: // load interceptor
210: ServiceInterceptor interceptor = ServiceInterceptorFactory
211: .load(this , Thread.currentThread()
212: .getContextClassLoader());
213: ServiceInterceptor si = container
214: .getSPI(ServiceInterceptor.class);
215: if (si != null) {
216: interceptor = ServiceInterceptor.aggregate(interceptor, si);
217: }
218: this .serviceInterceptor = interceptor;
219:
220: //if wsdl is null, try and get it from the WebServiceClient.wsdlLocation
221: if (wsdl == null) {
222: if (serviceClass != Service.class) {
223: WebServiceClient wsClient = AccessController
224: .doPrivileged(new PrivilegedAction<WebServiceClient>() {
225: public WebServiceClient run() {
226: return serviceClass
227: .getAnnotation(WebServiceClient.class);
228: }
229: });
230: String wsdlLocation = wsClient.wsdlLocation();
231: wsdlLocation = JAXWSUtils.absolutize(JAXWSUtils
232: .getFileOrURLName(wsdlLocation));
233: wsdl = new StreamSource(wsdlLocation);
234: }
235: }
236: WSDLServiceImpl service = null;
237: if (wsdl != null) {
238: try {
239: URL url = wsdl.getSystemId() == null ? null : new URL(
240: wsdl.getSystemId());
241: WSDLModelImpl model = parseWSDL(url, wsdl);
242: service = model.getService(this .serviceName);
243: if (service == null)
244: throw new WebServiceException(ClientMessages
245: .INVALID_SERVICE_NAME(this .serviceName,
246: buildNameList(model.getServices()
247: .keySet())));
248: // fill in statically known ports
249: for (WSDLPortImpl port : service.getPorts())
250: ports.put(port.getName(), new PortInfo(this , port));
251: } catch (MalformedURLException e) {
252: throw new WebServiceException(ClientMessages
253: .INVALID_WSDL_URL(wsdl.getSystemId()));
254: }
255: }
256: this .wsdlService = service;
257:
258: if (serviceClass != Service.class) {
259: //if @HandlerChain present, set HandlerResolver on service context
260: HandlerChain handlerChain = AccessController
261: .doPrivileged(new PrivilegedAction<HandlerChain>() {
262: public HandlerChain run() {
263: return serviceClass
264: .getAnnotation(HandlerChain.class);
265: }
266: });
267: if (handlerChain != null)
268: handlerConfigurator = new AnnotationConfigurator(this );
269: }
270:
271: }
272:
273: /**
274: * Parses the WSDL and builds {@link WSDLModel}.
275: * @param wsdlDocumentLocation
276: * Either this or <tt>wsdl</tt> parameter must be given.
277: * Null location means the system won't be able to resolve relative references in the WSDL,
278: */
279: private WSDLModelImpl parseWSDL(URL wsdlDocumentLocation,
280: Source wsdlSource) {
281: try {
282: return RuntimeWSDLParser.parse(wsdlDocumentLocation,
283: wsdlSource, createDefaultCatalogResolver(), true,
284: ServiceFinder.find(WSDLParserExtension.class)
285: .toArray());
286: } catch (IOException e) {
287: throw new WebServiceException(e);
288: } catch (XMLStreamException e) {
289: throw new WebServiceException(e);
290: } catch (SAXException e) {
291: throw new WebServiceException(e);
292: } catch (ServiceConfigurationError e) {
293: throw new WebServiceException(e);
294: }
295: }
296:
297: public Executor getExecutor() {
298: if (executor != null) {
299: return executor;
300: } else
301: executor = Executors
302: .newCachedThreadPool(new DaemonThreadFactory());
303: return executor;
304: }
305:
306: public void setExecutor(Executor executor) {
307: this .executor = executor;
308: }
309:
310: public HandlerResolver getHandlerResolver() {
311: return handlerConfigurator.getResolver();
312: }
313:
314: /*package*/final HandlerConfigurator getHandlerConfigurator() {
315: return handlerConfigurator;
316: }
317:
318: public void setHandlerResolver(HandlerResolver resolver) {
319: handlerConfigurator = new HandlerResolverImpl(resolver);
320: }
321:
322: public <T> T getPort(QName portName, Class<T> portInterface)
323: throws WebServiceException {
324: return getPort(portName, portInterface, EMPTY_FEATURES);
325: }
326:
327: public <T> T getPort(QName portName, Class<T> portInterface,
328: WebServiceFeature... features) {
329: if (portName == null || portInterface == null)
330: throw new IllegalArgumentException();
331: WSDLPortImpl portModel = getPortModel(portName);
332: return getPort(portModel.getEPR(), portName, portInterface,
333: features);
334: }
335:
336: public <T> T getPort(EndpointReference epr, Class<T> portInterface,
337: WebServiceFeature... features) {
338: return getPort(WSEndpointReference.create(epr), portInterface,
339: features);
340: }
341:
342: public <T> T getPort(WSEndpointReference wsepr,
343: Class<T> portInterface, WebServiceFeature... features) {
344: //get the portType from SEI, so that it can be used if EPR does n't have endpointName
345: QName portTypeName = RuntimeModeler
346: .getPortTypeName(portInterface);
347: //if port name is not specified in EPR, it will use portTypeName to get it from the WSDL model.
348: QName portName = getPortNameFromEPR(wsepr, portTypeName);
349: return getPort(wsepr, portName, portInterface, features);
350: }
351:
352: private <T> T getPort(WSEndpointReference wsepr, QName portName,
353: Class<T> portInterface, WebServiceFeature... features) {
354: addSEI(portName, portInterface);
355: return createEndpointIFBaseProxy(wsepr, portName,
356: portInterface, features);
357: }
358:
359: public <T> T getPort(Class<T> portInterface,
360: WebServiceFeature... features) {
361: //get the portType from SEI
362: QName portTypeName = RuntimeModeler
363: .getPortTypeName(portInterface);
364: //get the first port corresponding to the SEI
365: WSDLPortImpl port = wsdlService.getMatchingPort(portTypeName);
366: if (port == null)
367: throw new WebServiceException(ClientMessages
368: .UNDEFINED_PORT_TYPE(portTypeName));
369: QName portName = port.getName();
370: return getPort(portName, portInterface, features);
371: }
372:
373: public <T> T getPort(Class<T> portInterface)
374: throws WebServiceException {
375: return getPort(portInterface, EMPTY_FEATURES);
376: }
377:
378: public void addPort(QName portName, String bindingId,
379: String endpointAddress) throws WebServiceException {
380: if (!ports.containsKey(portName)) {
381: BindingID bid = (bindingId == null) ? BindingID.SOAP11_HTTP
382: : BindingID.parse(bindingId);
383: ports.put(portName, new PortInfo(this ,
384: (endpointAddress == null) ? null : EndpointAddress
385: .create(endpointAddress), portName, bid));
386: } else
387: throw new WebServiceException(DispatchMessages
388: .DUPLICATE_PORT(portName.toString()));
389: }
390:
391: public <T> Dispatch<T> createDispatch(QName portName,
392: Class<T> aClass, Service.Mode mode)
393: throws WebServiceException {
394: return createDispatch(portName, aClass, mode, EMPTY_FEATURES);
395: }
396:
397: @Override
398: public <T> Dispatch<T> createDispatch(QName portName,
399: WSEndpointReference wsepr, Class<T> aClass,
400: Service.Mode mode, WebServiceFeature... features) {
401: PortInfo port = safeGetPort(portName);
402: BindingImpl binding = port.createBinding(features, null);
403: Dispatch<T> dispatch = Stubs.createDispatch(portName, this ,
404: binding, aClass, mode, createPipeline(port, binding),
405: wsepr);
406: serviceInterceptor
407: .postCreateDispatch((WSBindingProvider) dispatch);
408: return dispatch;
409: }
410:
411: public <T> Dispatch<T> createDispatch(QName portName,
412: Class<T> aClass, Service.Mode mode,
413: WebServiceFeature... features) {
414: WebServiceFeatureList featureList = new WebServiceFeatureList(
415: features);
416: WSEndpointReference wsepr = null;
417: if (featureList.isEnabled(AddressingFeature.class)
418: && wsdlService != null
419: && wsdlService.get(portName) != null) {
420: wsepr = wsdlService.get(portName).getEPR();
421: }
422: return createDispatch(portName, wsepr, aClass, mode, features);
423: }
424:
425: public <T> Dispatch<T> createDispatch(
426: EndpointReference endpointReference, Class<T> type,
427: Service.Mode mode, WebServiceFeature... features) {
428: WSEndpointReference wsepr = new WSEndpointReference(
429: endpointReference);
430: QName portName = addPortEpr(wsepr);
431: return createDispatch(portName, wsepr, type, mode, features);
432: }
433:
434: /**
435: * Obtains {@link PortInfo} for the given name, with error check.
436: */
437: public @NotNull
438: PortInfo safeGetPort(QName portName) {
439: PortInfo port = ports.get(portName);
440: if (port == null) {
441: throw new WebServiceException(ClientMessages
442: .INVALID_PORT_NAME(portName, buildNameList(ports
443: .keySet())));
444: }
445: return port;
446: }
447:
448: private StringBuilder buildNameList(Collection<QName> names) {
449: StringBuilder sb = new StringBuilder();
450: for (QName qn : names) {
451: if (sb.length() > 0)
452: sb.append(',');
453: sb.append(qn);
454: }
455: return sb;
456: }
457:
458: /**
459: * Creates a new pipeline for the given port name.
460: */
461: private Tube createPipeline(PortInfo portInfo, WSBinding binding) {
462: //Check all required WSDL extensions are understood
463: checkAllWSDLExtensionsUnderstood(portInfo, binding);
464: SEIModel seiModel = null;
465: if (portInfo instanceof SEIPortInfo) {
466: seiModel = ((SEIPortInfo) portInfo).model;
467: }
468: BindingID bindingId = portInfo.bindingId;
469:
470: TubelineAssembler assembler = TubelineAssemblerFactory.create(
471: Thread.currentThread().getContextClassLoader(),
472: bindingId);
473: if (assembler == null)
474: throw new WebServiceException(
475: "Unable to process bindingID=" + bindingId); // TODO: i18n
476: return assembler.createClient(new ClientTubeAssemblerContext(
477: portInfo.targetEndpoint, portInfo.portModel, this ,
478: binding, container, ((BindingImpl) binding)
479: .createCodec(), seiModel));
480: }
481:
482: /**
483: * Checks only if RespectBindingFeature is enabled
484: * checks if all required wsdl extensions in the
485: * corresponding wsdl:Port are understood when RespectBindingFeature is enabled.
486: * @throws WebServiceException
487: * when any wsdl extension that has wsdl:required=true is not understood
488: */
489: private void checkAllWSDLExtensionsUnderstood(PortInfo port,
490: WSBinding binding) {
491: if (port.portModel != null
492: && binding
493: .isFeatureEnabled(RespectBindingFeature.class)) {
494: ((WSDLPortImpl) port.portModel)
495: .areRequiredExtensionsUnderstood();
496: }
497: }
498:
499: public EndpointAddress getEndpointAddress(QName qName) {
500: return ports.get(qName).targetEndpoint;
501: }
502:
503: public Dispatch<Object> createDispatch(QName portName,
504: JAXBContext jaxbContext, Service.Mode mode)
505: throws WebServiceException {
506: return createDispatch(portName, jaxbContext, mode,
507: EMPTY_FEATURES);
508: }
509:
510: @Override
511: public Dispatch<Object> createDispatch(QName portName,
512: WSEndpointReference wsepr, JAXBContext jaxbContext,
513: Service.Mode mode, WebServiceFeature... features) {
514: PortInfo port = safeGetPort(portName);
515: BindingImpl binding = port.createBinding(features, null);
516: Dispatch<Object> dispatch = Stubs.createJAXBDispatch(portName,
517: this , binding, jaxbContext, mode, createPipeline(port,
518: binding), wsepr);
519: serviceInterceptor
520: .postCreateDispatch((WSBindingProvider) dispatch);
521: return dispatch;
522: }
523:
524: @Override
525: public @NotNull
526: Container getContainer() {
527: return container;
528: }
529:
530: public Dispatch<Object> createDispatch(QName portName,
531: JAXBContext jaxbContext, Service.Mode mode,
532: WebServiceFeature... webServiceFeatures) {
533: WebServiceFeatureList featureList = new WebServiceFeatureList(
534: webServiceFeatures);
535: WSEndpointReference wsepr = null;
536: if (featureList.isEnabled(AddressingFeature.class)
537: && wsdlService != null
538: && wsdlService.get(portName) != null) {
539: wsepr = wsdlService.get(portName).getEPR();
540: }
541: return createDispatch(portName, wsepr, jaxbContext, mode,
542: webServiceFeatures);
543: }
544:
545: public Dispatch<Object> createDispatch(
546: EndpointReference endpointReference, JAXBContext context,
547: Service.Mode mode, WebServiceFeature... features) {
548: WSEndpointReference wsepr = new WSEndpointReference(
549: endpointReference);
550: QName portName = addPortEpr(wsepr);
551: return createDispatch(portName, wsepr, context, mode, features);
552: }
553:
554: private QName addPortEpr(WSEndpointReference wsepr) {
555: if (wsepr == null)
556: throw new WebServiceException(ProviderApiMessages
557: .NULL_EPR());
558: QName eprPortName = getPortNameFromEPR(wsepr, null);
559: //add Port, if it does n't exist;
560: // TODO: what if it has different epr address?
561: {
562: PortInfo portInfo = new PortInfo(this ,
563: (wsepr.getAddress() == null) ? null
564: : EndpointAddress
565: .create(wsepr.getAddress()),
566: eprPortName, getPortModel(eprPortName).getBinding()
567: .getBindingId());
568: if (!ports.containsKey(eprPortName)) {
569: ports.put(eprPortName, portInfo);
570: }
571: }
572: return eprPortName;
573: }
574:
575: /**
576: *
577: * @param wsepr EndpointReference from which portName will be extracted.
578: * If EndpointName ( port name) is null in EPR, then it will try to get if from WSDLModel using portType QName
579: * @param portTypeName
580: * should be null in dispatch case
581: * should be non null in SEI case
582: * @return
583: * port name from EPR after validating various metadat elements.
584: * Also if service instance does n't have wsdl,
585: * then it gets the WSDL metadata from EPR and builds wsdl model.
586: */
587: private QName getPortNameFromEPR(@NotNull
588: WSEndpointReference wsepr, @Nullable
589: QName portTypeName) {
590: QName portName;
591: WSEndpointReference.Metadata metadata = wsepr.getMetaData();
592: QName eprServiceName = metadata.getServiceName();
593: QName eprPortName = metadata.getPortName();
594: if ((eprServiceName != null)
595: && !eprServiceName.equals(serviceName)) {
596: throw new WebServiceException(
597: "EndpointReference WSDL ServiceName differs from Service Instance WSDL Service QName.\n"
598: + " The two Service QNames must match");
599: }
600: if (wsdlService == null) {
601: Source eprWsdlSource = metadata.getWsdlSource();
602: if (eprWsdlSource == null) {
603: throw new WebServiceException(ProviderApiMessages
604: .NULL_WSDL());
605: }
606: try {
607: WSDLModelImpl eprWsdlMdl = parseWSDL(new URL(wsepr
608: .getAddress()), eprWsdlSource);
609: wsdlService = eprWsdlMdl.getService(serviceName);
610: if (wsdlService == null)
611: throw new WebServiceException(ClientMessages
612: .INVALID_SERVICE_NAME(serviceName,
613: buildNameList(eprWsdlMdl
614: .getServices().keySet())));
615: } catch (MalformedURLException e) {
616: throw new WebServiceException(ClientMessages
617: .INVALID_ADDRESS(wsepr.getAddress()));
618: }
619: }
620: portName = eprPortName;
621:
622: if (portName == null && portTypeName != null) {
623: //get the first port corresponding to the SEI
624: WSDLPortImpl port = wsdlService
625: .getMatchingPort(portTypeName);
626: if (port == null)
627: throw new WebServiceException(ClientMessages
628: .UNDEFINED_PORT_TYPE(portTypeName));
629: portName = port.getName();
630: }
631: if (portName == null)
632: throw new WebServiceException(ProviderApiMessages
633: .NULL_PORTNAME());
634: if (wsdlService.get(portName) == null)
635: throw new WebServiceException(ClientMessages
636: .INVALID_EPR_PORT_NAME(portName,
637: buildWsdlPortNames()));
638:
639: return portName;
640:
641: }
642:
643: public QName getServiceName() {
644: return serviceName;
645: }
646:
647: protected Class getServiceClass() {
648: return serviceClass;
649: }
650:
651: public Iterator<QName> getPorts() throws WebServiceException {
652: // KK: the spec seems to be ambigous about whether
653: // this returns ports that are dynamically added or not.
654: if (ports.isEmpty())
655: throw new WebServiceException(
656: "dii.service.no.wsdl.available");
657: return ports.keySet().iterator();
658: }
659:
660: public URL getWSDLDocumentLocation() {
661: if (wsdlService == null)
662: return null;
663: try {
664: return new URL(wsdlService.getParent().getLocation()
665: .getSystemId());
666: } catch (MalformedURLException e) {
667: throw new AssertionError(e); // impossible
668: }
669: }
670:
671: private <T> T createEndpointIFBaseProxy(@Nullable
672: WSEndpointReference epr, QName portName, Class<T> portInterface,
673: WebServiceFeature[] webServiceFeatures) {
674: //fail if service doesnt have WSDL
675: if (wsdlService == null)
676: throw new WebServiceException(ClientMessages
677: .INVALID_SERVICE_NO_WSDL(serviceName));
678:
679: if (wsdlService.get(portName) == null) {
680: throw new WebServiceException(ClientMessages
681: .INVALID_PORT_NAME(portName, buildWsdlPortNames()));
682: }
683:
684: SEIPortInfo eif = seiContext.get(portName);
685:
686: BindingImpl binding = eif.createBinding(webServiceFeatures,
687: portInterface);
688: SEIStub pis = new SEIStub(this , binding, eif.model,
689: createPipeline(eif, binding), epr);
690:
691: T proxy = portInterface.cast(Proxy.newProxyInstance(
692: portInterface.getClassLoader(), new Class[] {
693: portInterface, WSBindingProvider.class,
694: Closeable.class }, pis));
695: if (serviceInterceptor != null) {
696: serviceInterceptor.postCreateProxy(
697: (WSBindingProvider) proxy, portInterface);
698: }
699: return proxy;
700: }
701:
702: /**
703: * Lists up the port names in WSDL. For error diagnostics.
704: */
705: private StringBuilder buildWsdlPortNames() {
706: Set<QName> wsdlPortNames = new HashSet<QName>();
707: for (WSDLPortImpl port : wsdlService.getPorts())
708: wsdlPortNames.add(port.getName());
709: return buildNameList(wsdlPortNames);
710: }
711:
712: /**
713: * Obtains a {@link WSDLPortImpl} with error check.
714: *
715: * @return guaranteed to be non-null.
716: */
717: public @NotNull
718: WSDLPortImpl getPortModel(QName portName) {
719: WSDLPortImpl port = wsdlService.get(portName);
720: if (port == null)
721: throw new WebServiceException(ClientMessages
722: .INVALID_PORT_NAME(portName, buildWsdlPortNames()));
723: return port;
724: }
725:
726: /**
727: * Contributes to the construction of {@link WSServiceDelegate} by filling in
728: * {@link SEIPortInfo} about a given SEI (linked from the {@link Service}-derived class.)
729: */
730: //todo: valid port in wsdl
731: private void addSEI(QName portName, Class portInterface)
732: throws WebServiceException {
733: SEIPortInfo spi = seiContext.get(portName);
734: if (spi != null)
735: return;
736: WSDLPortImpl wsdlPort = getPortModel(portName);
737: RuntimeModeler modeler = new RuntimeModeler(portInterface,
738: serviceName, wsdlPort);
739: modeler.setPortName(portName);
740: AbstractSEIModelImpl model = modeler.buildRuntimeModel();
741:
742: spi = new SEIPortInfo(this , portInterface,
743: (SOAPSEIModel) model, wsdlPort);
744: seiContext.put(spi.portName, spi);
745: //seiContext.put(spi.sei, spi);
746: ports.put(spi.portName, spi);
747:
748: }
749:
750: public WSDLServiceImpl getWsdlService() {
751: return wsdlService;
752: }
753:
754: class DaemonThreadFactory implements ThreadFactory {
755: public Thread newThread(Runnable r) {
756: Thread daemonThread = new Thread(r);
757: daemonThread.setDaemon(Boolean.TRUE);
758: return daemonThread;
759: }
760: }
761:
762: private static final WebServiceFeature[] EMPTY_FEATURES = new WebServiceFeature[0];
763: }
|