src/share/jaxws_classes/com/sun/xml/internal/ws/transport/http/server/EndpointImpl.java

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

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

merge

     1 /*
     2  * Copyright (c) 1997, 2012, 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.transport.http.server;
    28 import com.sun.istack.internal.Nullable;
    29 import com.sun.xml.internal.stream.buffer.XMLStreamBufferResult;
    30 import com.sun.xml.internal.ws.api.Component;
    31 import com.sun.xml.internal.ws.api.WSBinding;
    32 import com.sun.xml.internal.ws.api.BindingID;
    33 import com.sun.xml.internal.ws.api.databinding.MetadataReader;
    34 import com.sun.xml.internal.ws.api.message.Packet;
    35 import com.sun.xml.internal.ws.binding.BindingImpl;
    36 import com.sun.xml.internal.ws.api.server.*;
    37 import com.sun.xml.internal.ws.server.EndpointFactory;
    38 import com.sun.xml.internal.ws.server.ServerRtException;
    39 import com.sun.xml.internal.ws.util.xml.XmlUtil;
    40 import com.sun.xml.internal.ws.transport.http.HttpAdapterList;
    41 import com.sun.xml.internal.ws.transport.http.HttpAdapter;
    42 import com.sun.istack.internal.NotNull;
    44 import java.net.MalformedURLException;
    46 import javax.xml.namespace.QName;
    47 import javax.xml.transform.Source;
    48 import javax.xml.transform.TransformerException;
    49 import javax.xml.ws.*;
    50 import javax.xml.ws.spi.http.HttpContext;
    51 import javax.xml.ws.wsaddressing.W3CEndpointReference;
    52 import javax.xml.parsers.ParserConfigurationException;
    54 import java.io.IOException;
    55 import java.net.URL;
    56 import java.util.ArrayList;
    57 import java.util.Collections;
    58 import java.util.HashMap;
    59 import java.util.List;
    60 import java.util.Map;
    61 import java.util.concurrent.Executor;
    62 import java.lang.reflect.InvocationTargetException;
    63 import java.lang.reflect.Method;
    65 import org.xml.sax.EntityResolver;
    66 import org.xml.sax.SAXException;
    67 import org.w3c.dom.Element;
    70 /**
    71  * Implements {@link Endpoint}.
    72  * <p/>
    73  * <p/>
    74  * This class accumulates the information necessary to create
    75  * {@link WSEndpoint}, and then when {@link #publish} method
    76  * is called it will be created.
    77  * <p/>
    78  * <p/>
    79  * This object also allows accumulated information to be retrieved.
    80  *
    81  * @author Jitendra Kotamraju
    82  */
    83 public class EndpointImpl extends Endpoint {
    85     private static final WebServicePermission ENDPOINT_PUBLISH_PERMISSION =
    86             new WebServicePermission("publishEndpoint");
    88     /**
    89      * Once the service is published, this field will
    90      * be set to the {@link HttpEndpoint} instance.
    91      * <p/>
    92      * But don't declare the type as {@link HttpEndpoint}
    93      * to avoid static type dependency that cause the class loading to
    94      * fail if the LW HTTP server doesn't exist.
    95      */
    96     private Object actualEndpoint;
    98     // information accumulated for creating WSEndpoint
    99     private final WSBinding binding;
   100     private @Nullable final Object implementor;
   101     private List<Source> metadata;
   102     private Executor executor;
   103     private Map<String, Object> properties = Collections.emptyMap(); // always non-null
   104     private boolean stopped;
   105     private @Nullable EndpointContext endpointContext;
   106     private @NotNull final Class<?> implClass;
   107     private final Invoker invoker;
   108     private Container container;
   111     public EndpointImpl(@NotNull BindingID bindingId, @NotNull Object impl,
   112                         WebServiceFeature ... features) {
   113         this(bindingId, impl, impl.getClass(),
   114              InstanceResolver.createSingleton(impl).createInvoker(),  features);
   115     }
   117     public EndpointImpl(@NotNull BindingID bindingId, @NotNull Class implClass,
   118                         javax.xml.ws.spi.Invoker invoker,
   119                         WebServiceFeature ... features) {
   120         this(bindingId, null, implClass, new InvokerImpl(invoker),  features);
   121     }
   123     private EndpointImpl(@NotNull BindingID bindingId, Object impl, @NotNull Class implClass,
   124                         Invoker invoker, WebServiceFeature ... features) {
   125         binding = BindingImpl.create(bindingId, features);
   126         this.implClass = implClass;
   127         this.invoker = invoker;
   128         this.implementor = impl;
   129     }
   132     /**
   133      * Wraps an already created {@link WSEndpoint} into an {@link EndpointImpl},
   134      * and immediately publishes it with the given context.
   135      *
   136      * @param wse created endpoint
   137      * @param serverContext supported http context
   138      * @deprecated This is a backdoor method. Don't use it unless you know what you are doing.
   139      */
   140     public EndpointImpl(WSEndpoint wse, Object serverContext) {
   141         this(wse, serverContext, null);
   142     }
   144     /**
   145      * Wraps an already created {@link WSEndpoint} into an {@link EndpointImpl},
   146      * and immediately publishes it with the given context.
   147      *
   148      * @param wse created endpoint
   149      * @param serverContext supported http context
   150      * @param ctxt endpoint context
   151      * @deprecated This is a backdoor method. Don't use it unless you know what you are doing.
   152      */
   153     public EndpointImpl(WSEndpoint wse, Object serverContext, EndpointContext ctxt) {
   154         endpointContext = ctxt;
   155         actualEndpoint = new HttpEndpoint(null, getAdapter(wse, ""));
   156         ((HttpEndpoint) actualEndpoint).publish(serverContext);
   157         binding = wse.getBinding();
   158         implementor = null; // this violates the semantics, but hey, this is a backdoor.
   159         implClass = null;
   160         invoker = null;
   161     }
   163     /**
   164      * Wraps an already created {@link WSEndpoint} into an {@link EndpointImpl},
   165      * and immediately publishes it with the given context.
   166      *
   167      * @param wse created endpoint
   168      * @param address endpoint address
   169      * @deprecated This is a backdoor method. Don't use it unless you know what you are doing.
   170      */
   171     public EndpointImpl(WSEndpoint wse, String address) {
   172         this(wse, address, null);
   173     }
   176     /**
   177      * Wraps an already created {@link WSEndpoint} into an {@link EndpointImpl},
   178      * and immediately publishes it with the given context.
   179      *
   180      * @param wse created endpoint
   181      * @param address endpoint address
   182      * @param ctxt endpoint context
   183      * @deprecated This is a backdoor method. Don't use it unless you know what you are doing.
   184      */
   185     public EndpointImpl(WSEndpoint wse, String address, EndpointContext ctxt) {
   186         URL url;
   187         try {
   188             url = new URL(address);
   189         } catch (MalformedURLException ex) {
   190             throw new IllegalArgumentException("Cannot create URL for this address " + address);
   191         }
   192         if (!url.getProtocol().equals("http")) {
   193             throw new IllegalArgumentException(url.getProtocol() + " protocol based address is not supported");
   194         }
   195         if (!url.getPath().startsWith("/")) {
   196             throw new IllegalArgumentException("Incorrect WebService address=" + address +
   197                     ". The address's path should start with /");
   198         }
   199         endpointContext = ctxt;
   200         actualEndpoint = new HttpEndpoint(null, getAdapter(wse, url.getPath()));
   201         ((HttpEndpoint) actualEndpoint).publish(address);
   202         binding = wse.getBinding();
   203         implementor = null; // this violates the semantics, but hey, this is a backdoor.
   204         implClass = null;
   205         invoker = null;
   206     }
   208     public Binding getBinding() {
   209         return binding;
   210     }
   212     public Object getImplementor() {
   213         return implementor;
   214     }
   216     public void publish(String address) {
   217         canPublish();
   218         URL url;
   219         try {
   220             url = new URL(address);
   221         } catch (MalformedURLException ex) {
   222             throw new IllegalArgumentException("Cannot create URL for this address " + address);
   223         }
   224         if (!url.getProtocol().equals("http")) {
   225             throw new IllegalArgumentException(url.getProtocol() + " protocol based address is not supported");
   226         }
   227         if (!url.getPath().startsWith("/")) {
   228             throw new IllegalArgumentException("Incorrect WebService address=" + address +
   229                     ". The address's path should start with /");
   230         }
   231         createEndpoint(url.getPath());
   232         ((HttpEndpoint) actualEndpoint).publish(address);
   233     }
   235     public void publish(Object serverContext) {
   236         canPublish();
   237         if (!com.sun.net.httpserver.HttpContext.class.isAssignableFrom(serverContext.getClass())) {
   238             throw new IllegalArgumentException(serverContext.getClass() + " is not a supported context.");
   239         }
   240         createEndpoint(((com.sun.net.httpserver.HttpContext)serverContext).getPath());
   241         ((HttpEndpoint) actualEndpoint).publish(serverContext);
   242     }
   244     public void publish(HttpContext serverContext) {
   245         canPublish();
   246         createEndpoint(serverContext.getPath());
   247         ((HttpEndpoint) actualEndpoint).publish(serverContext);
   248     }
   250     public void stop() {
   251         if (isPublished()) {
   252             ((HttpEndpoint) actualEndpoint).stop();
   253             actualEndpoint = null;
   254             stopped = true;
   255         }
   256     }
   258     public boolean isPublished() {
   259         return actualEndpoint != null;
   260     }
   262     public List<Source> getMetadata() {
   263         return metadata;
   264     }
   266     public void setMetadata(java.util.List<Source> metadata) {
   267         if (isPublished()) {
   268             throw new IllegalStateException("Cannot set Metadata. Endpoint is already published");
   269         }
   270         this.metadata = metadata;
   271     }
   273     public Executor getExecutor() {
   274         return executor;
   275     }
   277     public void setExecutor(Executor executor) {
   278         this.executor = executor;
   279     }
   281     public Map<String, Object> getProperties() {
   282         return new HashMap<String, Object>(properties);
   283     }
   285     public void setProperties(Map<String, Object> map) {
   286         this.properties = new HashMap<String, Object>(map);
   287     }
   289     /*
   290     * Checks the permission of "publishEndpoint" before accessing HTTP classes.
   291     * Also it checks if there is an available HTTP server implementation.
   292     */
   293     private void createEndpoint(String urlPattern) {
   294         // Checks permission for "publishEndpoint"
   295         SecurityManager sm = System.getSecurityManager();
   296         if (sm != null) {
   297             sm.checkPermission(ENDPOINT_PUBLISH_PERMISSION);
   298         }
   300         // See if HttpServer implementation is available
   301         try {
   302             Class.forName("com.sun.net.httpserver.HttpServer");
   303         } catch (Exception e) {
   304             throw new UnsupportedOperationException("Couldn't load light weight http server", e);
   305         }
   306         container = getContainer();
   307         MetadataReader metadataReader = EndpointFactory.getExternalMetadatReader(implClass, binding);
   308         WSEndpoint wse = WSEndpoint.create(
   309                 implClass, true,
   310                 invoker,
   311                 getProperty(QName.class, Endpoint.WSDL_SERVICE),
   312                 getProperty(QName.class, Endpoint.WSDL_PORT),
   313                 container,
   314                 binding,
   315                 getPrimaryWsdl(metadataReader),
   316                 buildDocList(),
   317                 (EntityResolver) null,
   318                 false
   319         );
   320         // Don't load HttpEndpoint class before as it may load HttpServer classes
   321         actualEndpoint = new HttpEndpoint(executor, getAdapter(wse, urlPattern));
   322     }
   324     private <T> T getProperty(Class<T> type, String key) {
   325         Object o = properties.get(key);
   326         if (o == null) return null;
   327         if (type.isInstance(o))
   328             return type.cast(o);
   329         else
   330             throw new IllegalArgumentException("Property " + key + " has to be of type " + type);   // i18n
   331     }
   333     /**
   334      * Convert metadata sources using identity transform. So that we can
   335      * reuse the Source object multiple times.
   336      */
   337     private List<SDDocumentSource> buildDocList() {
   338         List<SDDocumentSource> r = new ArrayList<SDDocumentSource>();
   340         if (metadata != null) {
   341             for (Source source : metadata) {
   342                 try {
   343                     XMLStreamBufferResult xsbr = XmlUtil.identityTransform(source, new XMLStreamBufferResult());
   344                     String systemId = source.getSystemId();
   346                     r.add(SDDocumentSource.create(new URL(systemId), xsbr.getXMLStreamBuffer()));
   347                 } catch (TransformerException te) {
   348                     throw new ServerRtException("server.rt.err", te);
   349                 } catch (IOException te) {
   350                     throw new ServerRtException("server.rt.err", te);
   351                 } catch (SAXException e) {
   352                     throw new ServerRtException("server.rt.err", e);
   353                 } catch (ParserConfigurationException e) {
   354                     throw new ServerRtException("server.rt.err", e);
   355                 }
   356             }
   357         }
   359         return r;
   360     }
   362     /**
   363      * Gets wsdl from @WebService or @WebServiceProvider
   364      */
   365     private @Nullable SDDocumentSource getPrimaryWsdl(MetadataReader metadataReader) {
   366         // Takes care of @WebService, @WebServiceProvider's wsdlLocation
   367         EndpointFactory.verifyImplementorClass(implClass, metadataReader);
   368         String wsdlLocation = EndpointFactory.getWsdlLocation(implClass, metadataReader);
   369         if (wsdlLocation != null) {
   370             ClassLoader cl = implClass.getClassLoader();
   371             URL url = cl.getResource(wsdlLocation);
   372             if (url != null) {
   373                 return SDDocumentSource.create(url);
   374             }
   375             throw new ServerRtException("cannot.load.wsdl", wsdlLocation);
   376         }
   377         return null;
   378     }
   380     private void canPublish() {
   381         if (isPublished()) {
   382             throw new IllegalStateException(
   383                     "Cannot publish this endpoint. Endpoint has been already published.");
   384         }
   385         if (stopped) {
   386             throw new IllegalStateException(
   387                     "Cannot publish this endpoint. Endpoint has been already stopped.");
   388         }
   389     }
   391     public EndpointReference getEndpointReference(Element...referenceParameters) {
   392         return getEndpointReference(W3CEndpointReference.class, referenceParameters);
   393     }
   395     public <T extends EndpointReference> T getEndpointReference(Class<T> clazz, Element...referenceParameters) {
   396         if (!isPublished()) {
   397             throw new WebServiceException("Endpoint is not published yet");
   398         }
   399         return ((HttpEndpoint)actualEndpoint).getEndpointReference(clazz,referenceParameters);
   400     }
   402     @Override
   403     public void setEndpointContext(EndpointContext ctxt) {
   404         this.endpointContext = ctxt;
   405     }
   407     private HttpAdapter getAdapter(WSEndpoint endpoint, String urlPattern) {
   408         HttpAdapterList adapterList = null;
   409         if (endpointContext != null) {
   410                 if (endpointContext instanceof Component) {
   411                         adapterList = ((Component) endpointContext).getSPI(HttpAdapterList.class);
   412                 }
   414                 if (adapterList == null) {
   415                     for(Endpoint e : endpointContext.getEndpoints()) {
   416                         if (e.isPublished() && e != this) {
   417                             adapterList = ((HttpEndpoint)(((EndpointImpl)e).actualEndpoint)).getAdapterOwner();
   418                             assert adapterList != null;
   419                             break;
   420                         }
   421                     }
   422                 }
   423         }
   424         if (adapterList == null) {
   425             adapterList = new ServerAdapterList();
   426         }
   427         return adapterList.createAdapter("", urlPattern, endpoint);
   428     }
   430     /**
   431      * Endpoints within a EndpointContext get the same container.
   432      */
   433     private Container getContainer() {
   434         if (endpointContext != null) {
   435                 if (endpointContext instanceof Component) {
   436                         Container c = ((Component) endpointContext).getSPI(Container.class);
   437                         if (c != null)
   438                                 return c;
   439                 }
   441             for(Endpoint e : endpointContext.getEndpoints()) {
   442                 if (e.isPublished() && e != this) {
   443                     return ((EndpointImpl)e).container;
   444                 }
   445             }
   446         }
   447         return new ServerContainer();
   448     }
   450     private static class InvokerImpl extends Invoker {
   451         private javax.xml.ws.spi.Invoker spiInvoker;
   453         InvokerImpl(javax.xml.ws.spi.Invoker spiInvoker) {
   454             this.spiInvoker = spiInvoker;
   455         }
   457         @Override
   458         public void start(@NotNull WSWebServiceContext wsc, @NotNull WSEndpoint endpoint) {
   459             try {
   460                 spiInvoker.inject(wsc);
   461             } catch (IllegalAccessException e) {
   462                 throw new WebServiceException(e);
   463             } catch (InvocationTargetException e) {
   464                 throw new WebServiceException(e);
   465             }
   466         }
   468         public Object invoke(@NotNull Packet p, @NotNull Method m, @NotNull Object... args) throws InvocationTargetException, IllegalAccessException {
   469             return spiInvoker.invoke(m, args);
   470         }
   471     }
   472 }

mercurial