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 }