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 */
25
26package com.sun.xml.internal.ws.api;
27
28import com.sun.istack.internal.NotNull;
29import com.sun.istack.internal.Nullable;
30import com.sun.xml.internal.ws.api.addressing.WSEndpointReference;
31import com.sun.xml.internal.ws.api.server.Container;
32import com.sun.xml.internal.ws.api.server.ContainerResolver;
33import com.sun.xml.internal.ws.api.server.WSEndpoint;
34import com.sun.xml.internal.ws.client.WSServiceDelegate;
35
36import javax.xml.bind.JAXBContext;
37import javax.xml.namespace.QName;
38import javax.xml.ws.Dispatch;
39import javax.xml.ws.EndpointReference;
40import javax.xml.ws.Service;
41import javax.xml.ws.Service.Mode;
42import javax.xml.ws.WebServiceException;
43import javax.xml.ws.WebServiceFeature;
44import javax.xml.ws.spi.ServiceDelegate;
45import java.lang.reflect.Field;
46import java.net.URL;
47import java.security.AccessController;
48import java.security.PrivilegedAction;
49import java.util.HashSet;
50import java.util.Set;
51import 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 */
72public 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}
249