/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2012 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* http://glassfish.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package com.sun.xml.ws.api;
import com.sun.istack.NotNull;
import com.sun.istack.Nullable;
import com.sun.xml.ws.api.addressing.WSEndpointReference;
import com.sun.xml.ws.api.server.Container;
import com.sun.xml.ws.api.server.ContainerResolver;
import com.sun.xml.ws.api.server.WSEndpoint;
import com.sun.xml.ws.client.WSServiceDelegate;
import javax.xml.bind.JAXBContext;
import javax.xml.namespace.QName;
import javax.xml.ws.Dispatch;
import javax.xml.ws.EndpointReference;
import javax.xml.ws.Service;
import javax.xml.ws.Service.Mode;
import javax.xml.ws.WebServiceException;
import javax.xml.ws.WebServiceFeature;
import javax.xml.ws.spi.ServiceDelegate;
import java.lang.reflect.Field;
import java.net.URL;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* JAX-WS implementation of {@link ServiceDelegate}.
*
* <p>
* This abstract class is used only to improve the static type safety
* of the JAX-WS internal API.
*
* <p>
* The class name intentionally doesn't include "Delegate",
* because the fact that it's a delegate is a detail of
* the JSR-224 API, and for the layers above us this object
* nevertheless represents {@link Service}. We want them
* to think of this as an internal representation of a service.
*
* <p>
* Only JAX-WS internal code may downcast this to {@link WSServiceDelegate}.
*
* @author Kohsuke Kawaguchi
*/
public abstract class WSService extends ServiceDelegate implements ComponentRegistry {
private final Set<Component> components = new CopyOnWriteArraySet<Component>();
protected WSService() {
}
/**
* Works like {@link #getPort(EndpointReference, Class, WebServiceFeature...)}
* but takes {@link WSEndpointReference}.
*/
public abstract <T> T getPort(WSEndpointReference epr, Class<T> portInterface, WebServiceFeature... features);
/**
* Works like {@link #createDispatch(javax.xml.ws.EndpointReference, java.lang.Class, javax.xml.ws.Service.Mode, javax.xml.ws.WebServiceFeature[])}
* but it takes the port name separately, so that EPR without embedded metadata can be used.
*/
public abstract <T> Dispatch<T> createDispatch(QName portName, WSEndpointReference wsepr, Class<T> aClass, Service.Mode mode, WebServiceFeature... features);
/**
* Works like {@link #createDispatch(javax.xml.ws.EndpointReference, javax.xml.bind.JAXBContext, javax.xml.ws.Service.Mode, javax.xml.ws.WebServiceFeature[])}
* but it takes the port name separately, so that EPR without embedded metadata can be used.
*/
public abstract Dispatch<Object> createDispatch(QName portName, WSEndpointReference wsepr, JAXBContext jaxbContext, Service.Mode mode, WebServiceFeature... features);
/**
* Gets the {@link Container} object.
*
* <p>
* The components inside {@link WSEndpoint} uses this reference
* to communicate with the hosting environment.
*
* @return
* always same object. If no "real" {@link Container} instance
* is given, {@link Container#NONE} will be returned.
*/
public abstract @NotNull Container getContainer();
public @Nullable <S> S getSPI(@NotNull Class<S> spiType) {
for (Component c : components) {
S s = c.getSPI(spiType);
if (s != null)
return s;
}
return getContainer().getSPI(spiType);
}
public @NotNull Set<Component> getComponents() {
return components;
}
/**
* Create a <code>Service</code> instance.
*
* The specified WSDL document location and service qualified name MUST
* uniquely identify a <code>wsdl:service</code> element.
*
* @param wsdlDocumentLocation URL for the WSDL document location
* for the service
* @param serviceName QName for the service
* @throws WebServiceException If any error in creation of the
* specified service.
**/
public static WSService create( URL wsdlDocumentLocation, QName serviceName) {
return new WSServiceDelegate(wsdlDocumentLocation,serviceName,Service.class);
}
/**
* Create a <code>Service</code> instance.
*
* @param serviceName QName for the service
* @throws WebServiceException If any error in creation of the
* specified service
*/
public static WSService create(QName serviceName) {
return create(null,serviceName);
}
/**
* Creates a service with a dummy service name.
*/
public static WSService create() {
return create(null,new QName(WSService.class.getName(),"dummy"));
}
/**
* Typed parameter bag used by {@link WSService#create(URL, QName, InitParams)}
*
* @since 2.1.3
*/
public static final class InitParams {
private Container container;
/**
* Sets the {@link Container} object used by the created service.
* This allows the client to use a specific {@link Container} instance
* as opposed to the one obtained by {@link ContainerResolver}.
*/
public void setContainer(Container c) {
this.container = c;
}
public Container getContainer() {
return container;
}
}
/**
* To create a {@link Service}, we need to go through the API that doesn't let us
* pass parameters, so as a hack we use thread local.
*/
protected static final ThreadLocal<InitParams> INIT_PARAMS = new ThreadLocal<InitParams>();
/**
* Used as a immutable constant so that we can avoid null check.
*/
protected static final InitParams EMPTY_PARAMS = new InitParams();
/**
* Creates a {@link Service} instance.
*
* <p>
* This method works really like {@link Service#create(URL, QName)}
* except it takes one more RI specific parameter.
*
* @param wsdlDocumentLocation
* {@code URL} for the WSDL document location for the service.
* Can be null, in which case WSDL is not loaded.
* @param serviceName
* {@code QName} for the service.
* @param properties
* Additional RI specific initialization parameters. Can be null.
* @throws WebServiceException
* If any error in creation of the specified service.
**/
public static Service create( URL wsdlDocumentLocation, QName serviceName, InitParams properties) {
if(INIT_PARAMS.get()!=null)
throw new IllegalStateException("someone left non-null InitParams");
INIT_PARAMS.set(properties);
try {
Service svc = Service.create(wsdlDocumentLocation, serviceName);
if(INIT_PARAMS.get()!=null)
throw new IllegalStateException("Service "+svc+" didn't recognize InitParams");
return svc;
} finally {
// even in case of an exception still reset INIT_PARAMS
INIT_PARAMS.set(null);
}
}
/**
* Obtains the {@link WSService} that's encapsulated inside a {@link Service}.
*
* @throws IllegalArgumentException
* if the given service object is not from the JAX-WS RI.
*/
public static WSService unwrap(final Service svc) {
return AccessController.doPrivileged(new PrivilegedAction<WSService>() {
public WSService run() {
try {
Field f = svc.getClass().getField("delegate");
f.setAccessible(true);
Object delegate = f.get(svc);
if(!(delegate instanceof WSService))
throw new IllegalArgumentException();
return (WSService) delegate;
} catch (NoSuchFieldException e) {
AssertionError x = new AssertionError("Unexpected service API implementation");
x.initCause(e);
throw x;
} catch (IllegalAccessException e) {
IllegalAccessError x = new IllegalAccessError(e.getMessage());
x.initCause(e);
throw x;
}
}
});
}
}