View Javadoc
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   */
25  
26  package com.sun.xml.internal.ws.api;
27  
28  import com.sun.istack.internal.NotNull;
29  import com.sun.istack.internal.Nullable;
30  import com.sun.xml.internal.ws.api.addressing.WSEndpointReference;
31  import com.sun.xml.internal.ws.api.server.Container;
32  import com.sun.xml.internal.ws.api.server.ContainerResolver;
33  import com.sun.xml.internal.ws.api.server.WSEndpoint;
34  import com.sun.xml.internal.ws.client.WSServiceDelegate;
35  
36  import javax.xml.bind.JAXBContext;
37  import javax.xml.namespace.QName;
38  import javax.xml.ws.Dispatch;
39  import javax.xml.ws.EndpointReference;
40  import javax.xml.ws.Service;
41  import javax.xml.ws.Service.Mode;
42  import javax.xml.ws.WebServiceException;
43  import javax.xml.ws.WebServiceFeature;
44  import javax.xml.ws.spi.ServiceDelegate;
45  import java.lang.reflect.Field;
46  import java.net.URL;
47  import java.security.AccessController;
48  import java.security.PrivilegedAction;
49  import java.util.HashSet;
50  import java.util.Set;
51  import java.util.concurrent.CopyOnWriteArraySet;
52  
53  /**
54   * JAX-WS implementation of {@link ServiceDelegate}.
55   *
56   * <p>
57   * This abstract class is used only to improve the static type safety
58   * of the JAX-WS internal API.
59   *
60   * <p>
61   * The class name intentionally doesn't include "Delegate",
62   * because the fact that it's a delegate is a detail of
63   * the JSR-224 API, and for the layers above us this object
64   * nevertheless represents {@link Service}. We want them
65   * to think of this as an internal representation of a service.
66   *
67   * <p>
68   * Only JAX-WS internal code may downcast this to {@link WSServiceDelegate}.
69   *
70   * @author Kohsuke Kawaguchi
71   */
72  public abstract class WSService extends ServiceDelegate implements ComponentRegistry {
73          private final Set<Component> components = new CopyOnWriteArraySet<Component>();
74  
75          protected WSService() {
76      }
77  
78      /**
79       * Works like {@link #getPort(EndpointReference, Class, WebServiceFeature...)}
80       * but takes {@link WSEndpointReference}.
81       */
82      public abstract <T> T getPort(WSEndpointReference epr, Class<T> portInterface, WebServiceFeature... features);
83  
84      /**
85       * Works like {@link #createDispatch(javax.xml.ws.EndpointReference, java.lang.Class, javax.xml.ws.Service.Mode, javax.xml.ws.WebServiceFeature[])}
86       * but it takes the port name separately, so that EPR without embedded metadata can be used.
87       */
88      public abstract <T> Dispatch<T> createDispatch(QName portName, WSEndpointReference wsepr, Class<T> aClass, Service.Mode mode, WebServiceFeature... features);
89  
90      /**
91       * Works like {@link #createDispatch(javax.xml.ws.EndpointReference, javax.xml.bind.JAXBContext, javax.xml.ws.Service.Mode, javax.xml.ws.WebServiceFeature[])}
92       * but it takes the port name separately, so that EPR without embedded metadata can be used.
93       */
94      public abstract Dispatch<Object> createDispatch(QName portName, WSEndpointReference wsepr, JAXBContext jaxbContext, Service.Mode mode, WebServiceFeature... features);
95  
96      /**
97       * Gets the {@link Container} object.
98       *
99       * <p>
100      * The components inside {@link WSEndpoint} uses this reference
101      * to communicate with the hosting environment.
102      *
103      * @return
104      *      always same object. If no "real" {@link Container} instance
105      *      is given, {@link Container#NONE} will be returned.
106      */
107     public abstract @NotNull Container getContainer();
108 
109     public @Nullable <S> S getSPI(@NotNull Class<S> spiType) {
110         for (Component c : components) {
111                 S s = c.getSPI(spiType);
112                 if (s != null)
113                         return s;
114         }
115 
116         return getContainer().getSPI(spiType);
117     }
118 
119     public @NotNull Set<Component> getComponents() {
120         return components;
121     }
122 
123     /**
124      * Create a <code>Service</code> instance.
125      *
126      * The specified WSDL document location and service qualified name MUST
127      * uniquely identify a <code>wsdl:service</code> element.
128      *
129      * @param wsdlDocumentLocation URL for the WSDL document location
130      *                             for the service
131      * @param serviceName QName for the service
132      * @throws WebServiceException If any error in creation of the
133      *                    specified service.
134      **/
135     public static WSService create( URL wsdlDocumentLocation, QName serviceName) {
136         return new WSServiceDelegate(wsdlDocumentLocation,serviceName,Service.class);
137     }
138 
139     /**
140      * Create a <code>Service</code> instance.
141      *
142      * @param serviceName QName for the service
143      * @throws WebServiceException If any error in creation of the
144      *                    specified service
145      */
146     public static WSService create(QName serviceName) {
147         return create(null,serviceName);
148     }
149 
150     /**
151      * Creates a service with a dummy service name.
152      */
153     public static WSService create() {
154         return create(null,new QName(WSService.class.getName(),"dummy"));
155     }
156 
157     /**
158      * Typed parameter bag used by {@link WSService#create(URL, QName, InitParams)}
159      *
160      * @since 2.1.3
161      */
162     public static final class InitParams {
163         private Container container;
164         /**
165          * Sets the {@link Container} object used by the created service.
166          * This allows the client to use a specific {@link Container} instance
167          * as opposed to the one obtained by {@link ContainerResolver}.
168          */
169         public void setContainer(Container c) {
170             this.container = c;
171         }
172         public Container getContainer() {
173             return container;
174         }
175     }
176 
177     /**
178      * To create a {@link Service}, we need to go through the API that doesn't let us
179      * pass parameters, so as a hack we use thread local.
180      */
181     protected static final ThreadLocal<InitParams> INIT_PARAMS = new ThreadLocal<InitParams>();
182 
183     /**
184      * Used as a immutable constant so that we can avoid null check.
185      */
186     protected static final InitParams EMPTY_PARAMS = new InitParams();
187 
188     /**
189      * Creates a {@link Service} instance.
190      *
191      * <p>
192      * This method works really like {@link Service#create(URL, QName)}
193      * except it takes one more RI specific parameter.
194      *
195      * @param wsdlDocumentLocation
196      *          {@code URL} for the WSDL document location for the service.
197      *          Can be null, in which case WSDL is not loaded.
198      * @param serviceName
199      *          {@code QName} for the service.
200      * @param properties
201      *          Additional RI specific initialization parameters. Can be null.
202      * @throws WebServiceException
203      *          If any error in creation of the specified service.
204      **/
205     public static Service create( URL wsdlDocumentLocation, QName serviceName, InitParams properties) {
206         if(INIT_PARAMS.get()!=null)
207             throw new IllegalStateException("someone left non-null InitParams");
208         INIT_PARAMS.set(properties);
209         try {
210             Service svc = Service.create(wsdlDocumentLocation, serviceName);
211             if(INIT_PARAMS.get()!=null)
212                 throw new IllegalStateException("Service "+svc+" didn't recognize InitParams");
213             return svc;
214         } finally {
215             // even in case of an exception still reset INIT_PARAMS
216             INIT_PARAMS.set(null);
217         }
218     }
219 
220     /**
221      * Obtains the {@link WSService} that's encapsulated inside a {@link Service}.
222      *
223      * @throws IllegalArgumentException
224      *      if the given service object is not from the JAX-WS RI.
225      */
226     public static WSService unwrap(final Service svc) {
227         return AccessController.doPrivileged(new PrivilegedAction<WSService>() {
228             public WSService run() {
229                 try {
230                     Field f = svc.getClass().getField("delegate");
231                     f.setAccessible(true);
232                     Object delegate = f.get(svc);
233                     if(!(delegate instanceof WSService))
234                         throw new IllegalArgumentException();
235                     return (WSService) delegate;
236                 } catch (NoSuchFieldException e) {
237                     AssertionError x = new AssertionError("Unexpected service API implementation");
238                     x.initCause(e);
239                     throw x;
240                 } catch (IllegalAccessException e) {
241                     IllegalAccessError x = new IllegalAccessError(e.getMessage());
242                     x.initCause(e);
243                     throw x;
244                 }
245             }
246         });
247     }
248 }