src/share/jaxws_classes/com/sun/xml/internal/ws/client/WSServiceDelegate.java

Thu, 31 Aug 2017 15:18:52 +0800

author
aoqi
date
Thu, 31 Aug 2017 15:18:52 +0800
changeset 637
9c07ef4934dd
parent 408
b0610cd08440
parent 0
373ffda63c9a
permissions
-rw-r--r--

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 }

mercurial