| /* |
| * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package com.sun.xml.internal.ws.client; |
| |
| import com.sun.istack.internal.NotNull; |
| import com.sun.istack.internal.Nullable; |
| import com.sun.xml.internal.ws.Closeable; |
| import com.sun.xml.internal.ws.api.BindingID; |
| import com.sun.xml.internal.ws.api.ComponentFeature; |
| import com.sun.xml.internal.ws.api.ComponentsFeature; |
| import com.sun.xml.internal.ws.api.ComponentFeature.Target; |
| import com.sun.xml.internal.ws.api.EndpointAddress; |
| import com.sun.xml.internal.ws.api.WSService; |
| import com.sun.xml.internal.ws.api.addressing.WSEndpointReference; |
| import com.sun.xml.internal.ws.api.client.ServiceInterceptor; |
| import com.sun.xml.internal.ws.api.client.ServiceInterceptorFactory; |
| import com.sun.xml.internal.ws.api.databinding.DatabindingConfig; |
| import com.sun.xml.internal.ws.api.databinding.DatabindingFactory; |
| import com.sun.xml.internal.ws.api.databinding.MetadataReader; |
| import com.sun.xml.internal.ws.api.model.SEIModel; |
| import com.sun.xml.internal.ws.api.model.wsdl.WSDLModel; |
| import com.sun.xml.internal.ws.api.model.wsdl.WSDLPort; |
| import com.sun.xml.internal.ws.api.model.wsdl.WSDLService; |
| import com.sun.xml.internal.ws.api.pipe.Stubs; |
| import com.sun.xml.internal.ws.api.server.Container; |
| import com.sun.xml.internal.ws.api.server.ContainerResolver; |
| import com.sun.xml.internal.ws.api.wsdl.parser.WSDLParserExtension; |
| import com.sun.xml.internal.ws.binding.BindingImpl; |
| import com.sun.xml.internal.ws.binding.WebServiceFeatureList; |
| import com.sun.xml.internal.ws.client.HandlerConfigurator.AnnotationConfigurator; |
| import com.sun.xml.internal.ws.client.HandlerConfigurator.HandlerResolverImpl; |
| import com.sun.xml.internal.ws.client.sei.SEIStub; |
| import com.sun.xml.internal.ws.developer.MemberSubmissionAddressingFeature; |
| import com.sun.xml.internal.ws.developer.UsesJAXBContextFeature; |
| import com.sun.xml.internal.ws.developer.WSBindingProvider; |
| import com.sun.xml.internal.ws.model.RuntimeModeler; |
| import com.sun.xml.internal.ws.model.SOAPSEIModel; |
| import com.sun.xml.internal.ws.resources.ClientMessages; |
| import com.sun.xml.internal.ws.resources.DispatchMessages; |
| import com.sun.xml.internal.ws.resources.ProviderApiMessages; |
| import com.sun.xml.internal.ws.util.JAXWSUtils; |
| import com.sun.xml.internal.ws.util.ServiceConfigurationError; |
| import com.sun.xml.internal.ws.util.ServiceFinder; |
| import com.sun.xml.internal.ws.wsdl.parser.RuntimeWSDLParser; |
| |
| import org.xml.sax.EntityResolver; |
| import org.xml.sax.SAXException; |
| |
| import javax.jws.HandlerChain; |
| import javax.jws.WebService; |
| import javax.xml.bind.JAXBContext; |
| import javax.xml.namespace.QName; |
| import javax.xml.stream.XMLStreamException; |
| import javax.xml.transform.Source; |
| import javax.xml.transform.stream.StreamSource; |
| import javax.xml.ws.BindingProvider; |
| import javax.xml.ws.Dispatch; |
| import javax.xml.ws.EndpointReference; |
| import javax.xml.ws.Service; |
| import javax.xml.ws.WebServiceClient; |
| import javax.xml.ws.WebServiceException; |
| import javax.xml.ws.WebServiceFeature; |
| import javax.xml.ws.handler.HandlerResolver; |
| import javax.xml.ws.soap.AddressingFeature; |
| |
| import java.io.IOException; |
| import java.lang.reflect.InvocationHandler; |
| import java.lang.reflect.Proxy; |
| import java.net.MalformedURLException; |
| import java.net.URL; |
| import java.security.AccessController; |
| import java.security.PrivilegedAction; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.concurrent.Executor; |
| import java.util.concurrent.ThreadFactory; |
| |
| import static com.sun.xml.internal.ws.util.xml.XmlUtil.createDefaultCatalogResolver; |
| |
| /** |
| * <code>Service</code> objects provide the client view of a Web service. |
| * |
| * <p><code>Service</code> acts as a factory of the following: |
| * <ul> |
| * <li>Proxies for a target service endpoint. |
| * <li>Instances of <code>javax.xml.ws.Dispatch</code> for |
| * dynamic message-oriented invocation of a remote |
| * operation. |
| * </li> |
| * |
| * <p>The ports available on a service can be enumerated using the |
| * <code>getPorts</code> method. Alternatively, you can pass a |
| * service endpoint interface to the unary <code>getPort</code> method |
| * and let the runtime select a compatible port. |
| * |
| * <p>Handler chains for all the objects created by a <code>Service</code> |
| * can be set by means of the provided <code>HandlerRegistry</code>. |
| * |
| * <p>An <code>Executor</code> may be set on the service in order |
| * to gain better control over the threads used to dispatch asynchronous |
| * callbacks. For instance, thread pooling with certain parameters |
| * can be enabled by creating a <code>ThreadPoolExecutor</code> and |
| * registering it with the service. |
| * |
| * @author WS Development Team |
| * @see Executor |
| * @since JAX-WS 2.0 |
| */ |
| public class WSServiceDelegate extends WSService { |
| /** |
| * All ports. |
| * <p> |
| * This includes ports statically known to WSDL, as well as |
| * ones that are dynamically added |
| * through {@link #addPort(QName, String, String)}. |
| * <p> |
| * For statically known ports we'll have {@link SEIPortInfo}. |
| * For dynamically added ones we'll have {@link PortInfo}. |
| */ |
| private final Map<QName, PortInfo> ports = new HashMap<QName, PortInfo>(); |
| // For monitoring |
| protected Map<QName, PortInfo> getQNameToPortInfoMap() { return ports; } |
| |
| /** |
| * Whenever we create {@link BindingProvider}, we use this to configure handlers. |
| */ |
| private @NotNull HandlerConfigurator handlerConfigurator = new HandlerResolverImpl(null); |
| |
| private final Class<? extends Service> serviceClass; |
| |
| private final WebServiceFeatureList features; |
| |
| /** |
| * Name of the service for which this {@link WSServiceDelegate} is created for. |
| */ |
| private final @NotNull QName serviceName; |
| |
| /** |
| * Information about SEI, keyed by their interface type. |
| */ |
| // private final Map<Class,SEIPortInfo> seiContext = new HashMap<Class,SEIPortInfo>(); |
| private final Map<QName,SEIPortInfo> seiContext = new HashMap<QName,SEIPortInfo>(); |
| |
| // This executor is used for all the async invocations for all proxies |
| // created from this service. But once the proxy is created, then changing |
| // this executor doesn't affect the already created proxies. |
| private volatile Executor executor; |
| |
| /** |
| * The WSDL service that this {@link Service} object represents. |
| * <p> |
| * This field is null iff no WSDL is given to {@link Service}. |
| * This fiels can be be null if the service is created without wsdl but later |
| * the epr supplies a wsdl that can be parsed. |
| */ |
| private @Nullable WSDLService wsdlService; |
| |
| private final Container container; |
| /** |
| * Multiple {@link ServiceInterceptor}s are aggregated into one. |
| */ |
| /*package*/ final @NotNull ServiceInterceptor serviceInterceptor; |
| private URL wsdlURL; |
| |
| public WSServiceDelegate(URL wsdlDocumentLocation, QName serviceName, Class<? extends Service> serviceClass, WebServiceFeature... features) { |
| this(wsdlDocumentLocation, serviceName, serviceClass, new WebServiceFeatureList(features)); |
| } |
| |
| protected WSServiceDelegate(URL wsdlDocumentLocation, QName serviceName, Class<? extends Service> serviceClass, WebServiceFeatureList features) { |
| this( |
| wsdlDocumentLocation==null ? null : new StreamSource(wsdlDocumentLocation.toExternalForm()), |
| serviceName,serviceClass, features); |
| wsdlURL = wsdlDocumentLocation; |
| } |
| |
| /** |
| * @param serviceClass |
| * Either {@link Service}.class or other generated service-derived classes. |
| */ |
| public WSServiceDelegate(@Nullable Source wsdl, @NotNull QName serviceName, @NotNull final Class<? extends Service> serviceClass, WebServiceFeature... features) { |
| this(wsdl, serviceName, serviceClass, new WebServiceFeatureList(features)); |
| } |
| |
| /** |
| * @param serviceClass |
| * Either {@link Service}.class or other generated service-derived classes. |
| */ |
| protected WSServiceDelegate(@Nullable Source wsdl, @NotNull QName serviceName, @NotNull final Class<? extends Service> serviceClass, WebServiceFeatureList features) { |
| this(wsdl, null, serviceName, serviceClass, features); |
| } |
| |
| /** |
| * @param serviceClass |
| * Either {@link Service}.class or other generated service-derived classes. |
| */ |
| public WSServiceDelegate(@Nullable Source wsdl, @Nullable WSDLService service, @NotNull QName serviceName, @NotNull final Class<? extends Service> serviceClass, WebServiceFeature... features) { |
| this(wsdl, service, serviceName, serviceClass, new WebServiceFeatureList(features)); |
| } |
| |
| /** |
| * @param serviceClass |
| * Either {@link Service}.class or other generated service-derived classes. |
| */ |
| public WSServiceDelegate(@Nullable Source wsdl, @Nullable WSDLService service, @NotNull QName serviceName, @NotNull final Class<? extends Service> serviceClass, WebServiceFeatureList features) { |
| //we cant create a Service without serviceName |
| if (serviceName == null) { |
| throw new WebServiceException(ClientMessages.INVALID_SERVICE_NAME_NULL(null)); |
| } |
| |
| this.features = features; |
| |
| InitParams initParams = INIT_PARAMS.get(); |
| INIT_PARAMS.set(null); // mark it as consumed |
| if(initParams==null) { |
| initParams = EMPTY_PARAMS; |
| } |
| |
| this.serviceName = serviceName; |
| this.serviceClass = serviceClass; |
| Container tContainer = initParams.getContainer()!=null ? initParams.getContainer() : ContainerResolver.getInstance().getContainer(); |
| if (tContainer == Container.NONE) { |
| tContainer = new ClientContainer(); |
| } |
| this.container = tContainer; |
| |
| ComponentFeature cf = this.features.get(ComponentFeature.class); |
| if (cf != null) { |
| switch(cf.getTarget()) { |
| case SERVICE: |
| getComponents().add(cf.getComponent()); |
| break; |
| case CONTAINER: |
| this.container.getComponents().add(cf.getComponent()); |
| break; |
| default: |
| throw new IllegalArgumentException(); |
| } |
| } |
| ComponentsFeature csf = this.features.get(ComponentsFeature.class); |
| if (csf != null) { |
| for (ComponentFeature cfi : csf.getComponentFeatures()) { |
| switch(cfi.getTarget()) { |
| case SERVICE: |
| getComponents().add(cfi.getComponent()); |
| break; |
| case CONTAINER: |
| this.container.getComponents().add(cfi.getComponent()); |
| break; |
| default: |
| throw new IllegalArgumentException(); |
| } |
| } |
| } |
| |
| // load interceptor |
| ServiceInterceptor interceptor = ServiceInterceptorFactory.load(this, Thread.currentThread().getContextClassLoader()); |
| ServiceInterceptor si = container.getSPI(ServiceInterceptor.class); |
| if (si != null) { |
| interceptor = ServiceInterceptor.aggregate(interceptor, si); |
| } |
| this.serviceInterceptor = interceptor; |
| |
| if (service == null) { |
| //if wsdl is null, try and get it from the WebServiceClient.wsdlLocation |
| if(wsdl == null){ |
| if(serviceClass != Service.class){ |
| WebServiceClient wsClient = AccessController.doPrivileged(new PrivilegedAction<WebServiceClient>() { |
| public WebServiceClient run() { |
| return serviceClass.getAnnotation(WebServiceClient.class); |
| } |
| }); |
| String wsdlLocation = wsClient.wsdlLocation(); |
| wsdlLocation = JAXWSUtils.absolutize(JAXWSUtils.getFileOrURLName(wsdlLocation)); |
| wsdl = new StreamSource(wsdlLocation); |
| } |
| } |
| if (wsdl != null) { |
| try { |
| URL url = wsdl.getSystemId()==null ? null : JAXWSUtils.getEncodedURL(wsdl.getSystemId()); |
| WSDLModel model = parseWSDL(url, wsdl, serviceClass); |
| service = model.getService(this.serviceName); |
| if (service == null) |
| throw new WebServiceException( |
| ClientMessages.INVALID_SERVICE_NAME(this.serviceName, |
| buildNameList(model.getServices().keySet()))); |
| // fill in statically known ports |
| for (WSDLPort port : service.getPorts()) |
| ports.put(port.getName(), new PortInfo(this, port)); |
| } catch (MalformedURLException e) { |
| throw new WebServiceException(ClientMessages.INVALID_WSDL_URL(wsdl.getSystemId())); |
| } |
| } |
| } else { |
| // fill in statically known ports |
| for (WSDLPort port : service.getPorts()) |
| ports.put(port.getName(), new PortInfo(this, port)); |
| } |
| this.wsdlService = service; |
| |
| if (serviceClass != Service.class) { |
| //if @HandlerChain present, set HandlerResolver on service context |
| HandlerChain handlerChain = |
| AccessController.doPrivileged(new PrivilegedAction<HandlerChain>() { |
| public HandlerChain run() { |
| return serviceClass.getAnnotation(HandlerChain.class); |
| } |
| }); |
| if (handlerChain != null) |
| handlerConfigurator = new AnnotationConfigurator(this); |
| } |
| |
| } |
| |
| /** |
| * Parses the WSDL and builds {@link com.sun.xml.internal.ws.api.model.wsdl.WSDLModel}. |
| * @param wsdlDocumentLocation |
| * Either this or {@code wsdl} parameter must be given. |
| * Null location means the system won't be able to resolve relative references in the WSDL. |
| */ |
| private WSDLModel parseWSDL(URL wsdlDocumentLocation, Source wsdlSource, Class serviceClass) { |
| try { |
| return RuntimeWSDLParser.parse(wsdlDocumentLocation, wsdlSource, createCatalogResolver(), |
| true, getContainer(), serviceClass, ServiceFinder.find(WSDLParserExtension.class).toArray()); |
| } catch (IOException e) { |
| throw new WebServiceException(e); |
| } catch (XMLStreamException e) { |
| throw new WebServiceException(e); |
| } catch (SAXException e) { |
| throw new WebServiceException(e); |
| } catch (ServiceConfigurationError e) { |
| throw new WebServiceException(e); |
| } |
| } |
| |
| protected EntityResolver createCatalogResolver() { |
| return createDefaultCatalogResolver(); |
| } |
| |
| public Executor getExecutor() { |
| return executor; |
| } |
| |
| public void setExecutor(Executor executor) { |
| this.executor = executor; |
| } |
| |
| public HandlerResolver getHandlerResolver() { |
| return handlerConfigurator.getResolver(); |
| } |
| |
| /*package*/ final HandlerConfigurator getHandlerConfigurator() { |
| return handlerConfigurator; |
| } |
| |
| public void setHandlerResolver(HandlerResolver resolver) { |
| handlerConfigurator = new HandlerResolverImpl(resolver); |
| } |
| |
| public <T> T getPort(QName portName, Class<T> portInterface) throws WebServiceException { |
| return getPort(portName, portInterface, EMPTY_FEATURES); |
| } |
| |
| public <T> T getPort(QName portName, Class<T> portInterface, WebServiceFeature... features) { |
| if (portName == null || portInterface == null) |
| throw new IllegalArgumentException(); |
| WSDLService tWsdlService = this.wsdlService; |
| if (tWsdlService == null) { |
| // assigning it to local variable and not setting it back to this.wsdlService intentionally |
| // as we don't want to include the service instance with information gathered from sei |
| tWsdlService = getWSDLModelfromSEI(portInterface); |
| //still null? throw error need wsdl metadata to create a proxy |
| if (tWsdlService == null) { |
| throw new WebServiceException(ProviderApiMessages.NO_WSDL_NO_PORT(portInterface.getName())); |
| } |
| |
| } |
| WSDLPort portModel = getPortModel(tWsdlService, portName); |
| return getPort(portModel.getEPR(), portName, portInterface, new WebServiceFeatureList(features)); |
| } |
| |
| public <T> T getPort(EndpointReference epr, Class<T> portInterface, WebServiceFeature... features) { |
| return getPort(WSEndpointReference.create(epr),portInterface,features); |
| } |
| |
| public <T> T getPort(WSEndpointReference wsepr, Class<T> portInterface, WebServiceFeature... features) { |
| //get the portType from SEI, so that it can be used if EPR does n't have endpointName |
| WebServiceFeatureList featureList = new WebServiceFeatureList(features); |
| QName portTypeName = RuntimeModeler.getPortTypeName(portInterface, getMetadadaReader(featureList, portInterface.getClassLoader())); |
| //if port name is not specified in EPR, it will use portTypeName to get it from the WSDL model. |
| QName portName = getPortNameFromEPR(wsepr, portTypeName); |
| return getPort(wsepr,portName,portInterface, featureList); |
| } |
| |
| protected <T> T getPort(WSEndpointReference wsepr, QName portName, Class<T> portInterface, |
| WebServiceFeatureList features) { |
| ComponentFeature cf = features.get(ComponentFeature.class); |
| if (cf != null && !Target.STUB.equals(cf.getTarget())) { |
| throw new IllegalArgumentException(); |
| } |
| ComponentsFeature csf = features.get(ComponentsFeature.class); |
| if (csf != null) { |
| for (ComponentFeature cfi : csf.getComponentFeatures()) { |
| if (!Target.STUB.equals(cfi.getTarget())) |
| throw new IllegalArgumentException(); |
| } |
| } |
| features.addAll(this.features); |
| |
| SEIPortInfo spi = addSEI(portName, portInterface, features); |
| return createEndpointIFBaseProxy(wsepr,portName,portInterface,features, spi); |
| } |
| |
| @Override |
| public <T> T getPort(Class<T> portInterface, WebServiceFeature... features) { |
| //get the portType from SEI |
| QName portTypeName = RuntimeModeler.getPortTypeName(portInterface, getMetadadaReader(new WebServiceFeatureList(features), portInterface.getClassLoader())); |
| WSDLService tmpWsdlService = this.wsdlService; |
| if (tmpWsdlService == null) { |
| // assigning it to local variable and not setting it back to this.wsdlService intentionally |
| // as we don't want to include the service instance with information gathered from sei |
| tmpWsdlService = getWSDLModelfromSEI(portInterface); |
| //still null? throw error need wsdl metadata to create a proxy |
| if(tmpWsdlService == null) { |
| throw new WebServiceException(ProviderApiMessages.NO_WSDL_NO_PORT(portInterface.getName())); |
| } |
| } |
| //get the first port corresponding to the SEI |
| WSDLPort port = tmpWsdlService.getMatchingPort(portTypeName); |
| if (port == null) { |
| throw new WebServiceException(ClientMessages.UNDEFINED_PORT_TYPE(portTypeName)); |
| } |
| QName portName = port.getName(); |
| return getPort(portName, portInterface,features); |
| } |
| |
| public <T> T getPort(Class<T> portInterface) throws WebServiceException { |
| return getPort(portInterface, EMPTY_FEATURES); |
| } |
| |
| public void addPort(QName portName, String bindingId, String endpointAddress) throws WebServiceException { |
| if (!ports.containsKey(portName)) { |
| BindingID bid = (bindingId == null) ? BindingID.SOAP11_HTTP : BindingID.parse(bindingId); |
| ports.put(portName, |
| new PortInfo(this, (endpointAddress == null) ? null : |
| EndpointAddress.create(endpointAddress), portName, bid)); |
| } else |
| throw new WebServiceException(DispatchMessages.DUPLICATE_PORT(portName.toString())); |
| } |
| |
| |
| public <T> Dispatch<T> createDispatch(QName portName, Class<T> aClass, Service.Mode mode) throws WebServiceException { |
| return createDispatch(portName, aClass, mode, EMPTY_FEATURES); |
| } |
| |
| @Override |
| public <T> Dispatch<T> createDispatch(QName portName, WSEndpointReference wsepr, Class<T> aClass, Service.Mode mode, WebServiceFeature... features) { |
| return createDispatch(portName, wsepr, aClass, mode, new WebServiceFeatureList(features)); |
| } |
| |
| public <T> Dispatch<T> createDispatch(QName portName, WSEndpointReference wsepr, Class<T> aClass, Service.Mode mode, WebServiceFeatureList features) { |
| PortInfo port = safeGetPort(portName); |
| |
| ComponentFeature cf = features.get(ComponentFeature.class); |
| if (cf != null && !Target.STUB.equals(cf.getTarget())) { |
| throw new IllegalArgumentException(); |
| } |
| ComponentsFeature csf = features.get(ComponentsFeature.class); |
| if (csf != null) { |
| for (ComponentFeature cfi : csf.getComponentFeatures()) { |
| if (!Target.STUB.equals(cfi.getTarget())) |
| throw new IllegalArgumentException(); |
| } |
| } |
| features.addAll(this.features); |
| |
| BindingImpl binding = port.createBinding(features, null, null); |
| binding.setMode(mode); |
| Dispatch<T> dispatch = Stubs.createDispatch(port, this, binding, aClass, mode, wsepr); |
| serviceInterceptor.postCreateDispatch((WSBindingProvider) dispatch); |
| return dispatch; |
| } |
| |
| public <T> Dispatch<T> createDispatch(QName portName, Class<T> aClass, Service.Mode mode, WebServiceFeature... features) { |
| return createDispatch(portName, aClass, mode, new WebServiceFeatureList(features)); |
| } |
| |
| public <T> Dispatch<T> createDispatch(QName portName, Class<T> aClass, Service.Mode mode, WebServiceFeatureList features) { |
| WSEndpointReference wsepr = null; |
| boolean isAddressingEnabled = false; |
| AddressingFeature af = features.get(AddressingFeature.class); |
| if (af == null) { |
| af = this.features.get(AddressingFeature.class); |
| } |
| if (af != null && af.isEnabled()) |
| isAddressingEnabled = true; |
| MemberSubmissionAddressingFeature msa = features.get(MemberSubmissionAddressingFeature.class); |
| if (msa == null) { |
| msa = this.features.get(MemberSubmissionAddressingFeature.class); |
| } |
| if (msa != null && msa.isEnabled()) |
| isAddressingEnabled = true; |
| if(isAddressingEnabled && wsdlService != null && wsdlService.get(portName) != null) { |
| wsepr = wsdlService.get(portName).getEPR(); |
| } |
| return createDispatch(portName, wsepr, aClass, mode, features); |
| } |
| |
| public <T> Dispatch<T> createDispatch(EndpointReference endpointReference, Class<T> type, Service.Mode mode, WebServiceFeature... features) { |
| WSEndpointReference wsepr = new WSEndpointReference(endpointReference); |
| QName portName = addPortEpr(wsepr); |
| return createDispatch(portName, wsepr, type, mode, features); |
| } |
| |
| /** |
| * Obtains {@link PortInfo} for the given name, with error check. |
| */ |
| public |
| @NotNull |
| PortInfo safeGetPort(QName portName) { |
| PortInfo port = ports.get(portName); |
| if (port == null) { |
| throw new WebServiceException(ClientMessages.INVALID_PORT_NAME(portName, buildNameList(ports.keySet()))); |
| } |
| return port; |
| } |
| |
| private StringBuilder buildNameList(Collection<QName> names) { |
| StringBuilder sb = new StringBuilder(); |
| for (QName qn : names) { |
| if (sb.length() > 0) sb.append(','); |
| sb.append(qn); |
| } |
| return sb; |
| } |
| |
| public EndpointAddress getEndpointAddress(QName qName) { |
| PortInfo p = ports.get(qName); |
| return p != null ? p.targetEndpoint : null; |
| } |
| |
| public Dispatch<Object> createDispatch(QName portName, JAXBContext jaxbContext, Service.Mode mode) throws WebServiceException { |
| return createDispatch(portName, jaxbContext, mode, EMPTY_FEATURES); |
| } |
| |
| @Override |
| public Dispatch<Object> createDispatch(QName portName, WSEndpointReference wsepr, JAXBContext jaxbContext, Service.Mode mode, WebServiceFeature... features) { |
| return createDispatch(portName, wsepr, jaxbContext, mode, new WebServiceFeatureList(features)); |
| } |
| |
| protected Dispatch<Object> createDispatch(QName portName, WSEndpointReference wsepr, JAXBContext jaxbContext, Service.Mode mode, WebServiceFeatureList features) { |
| PortInfo port = safeGetPort(portName); |
| |
| ComponentFeature cf = features.get(ComponentFeature.class); |
| if (cf != null && !Target.STUB.equals(cf.getTarget())) { |
| throw new IllegalArgumentException(); |
| } |
| ComponentsFeature csf = features.get(ComponentsFeature.class); |
| if (csf != null) { |
| for (ComponentFeature cfi : csf.getComponentFeatures()) { |
| if (!Target.STUB.equals(cfi.getTarget())) |
| throw new IllegalArgumentException(); |
| } |
| } |
| features.addAll(this.features); |
| |
| BindingImpl binding = port.createBinding(features, null, null); |
| binding.setMode(mode); |
| Dispatch<Object> dispatch = Stubs.createJAXBDispatch( |
| port, binding, jaxbContext, mode,wsepr); |
| serviceInterceptor.postCreateDispatch((WSBindingProvider)dispatch); |
| return dispatch; |
| } |
| |
| @Override |
| public @NotNull Container getContainer() { |
| return container; |
| } |
| |
| public Dispatch<Object> createDispatch(QName portName, JAXBContext jaxbContext, Service.Mode mode, WebServiceFeature... webServiceFeatures) { |
| return createDispatch(portName, jaxbContext, mode, new WebServiceFeatureList(webServiceFeatures)); |
| } |
| |
| protected Dispatch<Object> createDispatch(QName portName, JAXBContext jaxbContext, Service.Mode mode, WebServiceFeatureList features) { |
| WSEndpointReference wsepr = null; |
| boolean isAddressingEnabled = false; |
| AddressingFeature af = features.get(AddressingFeature.class); |
| if (af == null) { |
| af = this.features.get(AddressingFeature.class); |
| } |
| if (af != null && af.isEnabled()) |
| isAddressingEnabled = true; |
| MemberSubmissionAddressingFeature msa = features.get(MemberSubmissionAddressingFeature.class); |
| if (msa == null) { |
| msa = this.features.get(MemberSubmissionAddressingFeature.class); |
| } |
| if (msa != null && msa.isEnabled()) |
| isAddressingEnabled = true; |
| if(isAddressingEnabled && wsdlService != null && wsdlService.get(portName) != null) { |
| wsepr = wsdlService.get(portName).getEPR(); |
| } |
| return createDispatch(portName, wsepr, jaxbContext, mode, features); |
| } |
| |
| public Dispatch<Object> createDispatch(EndpointReference endpointReference, JAXBContext context, Service.Mode mode, WebServiceFeature... features) { |
| WSEndpointReference wsepr = new WSEndpointReference(endpointReference); |
| QName portName = addPortEpr(wsepr); |
| return createDispatch(portName, wsepr, context, mode, features); |
| } |
| |
| private QName addPortEpr(WSEndpointReference wsepr) { |
| if (wsepr == null) |
| throw new WebServiceException(ProviderApiMessages.NULL_EPR()); |
| QName eprPortName = getPortNameFromEPR(wsepr, null); |
| //add Port, if it does n't exist; |
| // TODO: what if it has different epr address? |
| { |
| PortInfo portInfo = new PortInfo(this, (wsepr.getAddress() == null) ? null : EndpointAddress.create(wsepr.getAddress()), eprPortName, |
| getPortModel(wsdlService, eprPortName).getBinding().getBindingId()); |
| if (!ports.containsKey(eprPortName)) { |
| ports.put(eprPortName, portInfo); |
| } |
| } |
| return eprPortName; |
| } |
| |
| /** |
| * |
| * @param wsepr EndpointReference from which portName will be extracted. |
| * If EndpointName ( port name) is null in EPR, then it will try to get if from WSDLModel using portType QName |
| * @param portTypeName |
| * should be null in dispatch case |
| * should be non null in SEI case |
| * @return |
| * port name from EPR after validating various metadat elements. |
| * Also if service instance does n't have wsdl, |
| * then it gets the WSDL metadata from EPR and builds wsdl model. |
| */ |
| private QName getPortNameFromEPR(@NotNull WSEndpointReference wsepr, @Nullable QName portTypeName) { |
| QName portName; |
| WSEndpointReference.Metadata metadata = wsepr.getMetaData(); |
| QName eprServiceName = metadata.getServiceName(); |
| QName eprPortName = metadata.getPortName(); |
| if ((eprServiceName != null ) && !eprServiceName.equals(serviceName)) { |
| throw new WebServiceException("EndpointReference WSDL ServiceName differs from Service Instance WSDL Service QName.\n" |
| + " The two Service QNames must match"); |
| } |
| if (wsdlService == null) { |
| Source eprWsdlSource = metadata.getWsdlSource(); |
| if (eprWsdlSource == null) { |
| throw new WebServiceException(ProviderApiMessages.NULL_WSDL()); |
| } |
| try { |
| WSDLModel eprWsdlMdl = parseWSDL(new URL(wsepr.getAddress()), eprWsdlSource, null); |
| wsdlService = eprWsdlMdl.getService(serviceName); |
| if (wsdlService == null) |
| throw new WebServiceException(ClientMessages.INVALID_SERVICE_NAME(serviceName, |
| buildNameList(eprWsdlMdl.getServices().keySet()))); |
| } catch (MalformedURLException e) { |
| throw new WebServiceException(ClientMessages.INVALID_ADDRESS(wsepr.getAddress())); |
| } |
| } |
| portName = eprPortName; |
| |
| if (portName == null && portTypeName != null) { |
| //get the first port corresponding to the SEI |
| WSDLPort port = wsdlService.getMatchingPort(portTypeName); |
| if (port == null) |
| throw new WebServiceException(ClientMessages.UNDEFINED_PORT_TYPE(portTypeName)); |
| portName = port.getName(); |
| } |
| if (portName == null) |
| throw new WebServiceException(ProviderApiMessages.NULL_PORTNAME()); |
| if (wsdlService.get(portName) == null) |
| throw new WebServiceException(ClientMessages.INVALID_EPR_PORT_NAME(portName, buildWsdlPortNames())); |
| |
| return portName; |
| |
| } |
| |
| private <T> T createProxy(final Class<T> portInterface, final InvocationHandler pis) { |
| |
| // When creating the proxy, use a ClassLoader that can load classes |
| // from both the interface class and also from this classes |
| // classloader. This is necessary when this code is used in systems |
| // such as OSGi where the class loader for the interface class may |
| // not be able to load internal JAX-WS classes like |
| // "WSBindingProvider", but the class loader for this class may not |
| // be able to load the interface class. |
| final ClassLoader loader = getDelegatingLoader(portInterface.getClassLoader(), |
| WSServiceDelegate.class.getClassLoader()); |
| |
| return AccessController.doPrivileged( |
| new PrivilegedAction<T>() { |
| @Override |
| public T run() { |
| Object proxy = Proxy.newProxyInstance(loader, |
| new Class[]{portInterface, WSBindingProvider.class, Closeable.class}, pis); |
| return portInterface.cast(proxy); |
| } |
| }); |
| |
| } |
| |
| private WSDLService getWSDLModelfromSEI(final Class sei) { |
| WebService ws = AccessController.doPrivileged(new PrivilegedAction<WebService>() { |
| public WebService run() { |
| return (WebService) sei.getAnnotation(WebService.class); |
| } |
| }); |
| if (ws == null || ws.wsdlLocation().equals("")) |
| return null; |
| String wsdlLocation = ws.wsdlLocation(); |
| wsdlLocation = JAXWSUtils.absolutize(JAXWSUtils.getFileOrURLName(wsdlLocation)); |
| Source wsdl = new StreamSource(wsdlLocation); |
| WSDLService service = null; |
| |
| try { |
| URL url = wsdl.getSystemId() == null ? null : new URL(wsdl.getSystemId()); |
| WSDLModel model = parseWSDL(url, wsdl, sei); |
| service = model.getService(this.serviceName); |
| if (service == null) |
| throw new WebServiceException( |
| ClientMessages.INVALID_SERVICE_NAME(this.serviceName, |
| buildNameList(model.getServices().keySet()))); |
| } catch (MalformedURLException e) { |
| throw new WebServiceException(ClientMessages.INVALID_WSDL_URL(wsdl.getSystemId())); |
| } |
| return service; |
| } |
| |
| public QName getServiceName() { |
| return serviceName; |
| } |
| |
| public Class getServiceClass() { |
| return serviceClass; |
| } |
| |
| public Iterator<QName> getPorts() throws WebServiceException { |
| // KK: the spec seems to be ambigous about whether |
| // this returns ports that are dynamically added or not. |
| return ports.keySet().iterator(); |
| } |
| |
| @Override |
| public URL getWSDLDocumentLocation() { |
| if(wsdlService==null) return null; |
| try { |
| return new URL(wsdlService.getParent().getLocation().getSystemId()); |
| } catch (MalformedURLException e) { |
| throw new AssertionError(e); // impossible |
| } |
| } |
| |
| private <T> T createEndpointIFBaseProxy(@Nullable WSEndpointReference epr, QName portName, Class<T> portInterface, |
| WebServiceFeatureList webServiceFeatures, SEIPortInfo eif) { |
| //fail if service doesnt have WSDL |
| if (wsdlService == null) { |
| throw new WebServiceException(ClientMessages.INVALID_SERVICE_NO_WSDL(serviceName)); |
| } |
| |
| if (wsdlService.get(portName)==null) { |
| throw new WebServiceException( |
| ClientMessages.INVALID_PORT_NAME(portName,buildWsdlPortNames())); |
| } |
| |
| BindingImpl binding = eif.createBinding(webServiceFeatures, portInterface); |
| InvocationHandler pis = getStubHandler(binding, eif, epr); |
| |
| T proxy = createProxy(portInterface, pis); |
| |
| if (serviceInterceptor != null) { |
| serviceInterceptor.postCreateProxy((WSBindingProvider)proxy, portInterface); |
| } |
| return proxy; |
| } |
| |
| protected InvocationHandler getStubHandler(BindingImpl binding, SEIPortInfo eif, @Nullable WSEndpointReference epr) { |
| return new SEIStub(eif, binding, eif.model, epr); |
| } |
| |
| /** |
| * Lists up the port names in WSDL. For error diagnostics. |
| */ |
| private StringBuilder buildWsdlPortNames() { |
| Set<QName> wsdlPortNames = new HashSet<QName>(); |
| for (WSDLPort port : wsdlService.getPorts()) { |
| wsdlPortNames.add(port.getName()); |
| } |
| return buildNameList(wsdlPortNames); |
| } |
| |
| /** |
| * Obtains a {@link WSDLPortImpl} with error check. |
| * |
| * @return guaranteed to be non-null. |
| */ |
| public @NotNull WSDLPort getPortModel(WSDLService wsdlService, QName portName) { |
| WSDLPort port = wsdlService.get(portName); |
| if (port == null) |
| throw new WebServiceException( |
| ClientMessages.INVALID_PORT_NAME(portName,buildWsdlPortNames())); |
| return port; |
| } |
| |
| /** |
| * Contributes to the construction of {@link WSServiceDelegate} by filling in |
| * {@link SEIPortInfo} about a given SEI (linked from the {@link Service}-derived class.) |
| */ |
| //todo: valid port in wsdl |
| private SEIPortInfo addSEI(QName portName, Class portInterface, WebServiceFeatureList features) throws WebServiceException { |
| boolean ownModel = useOwnSEIModel(features); |
| if (ownModel) { |
| // Create a new model and do not cache it |
| return createSEIPortInfo(portName, portInterface, features); |
| } |
| |
| SEIPortInfo spi = seiContext.get(portName); |
| if (spi == null) { |
| spi = createSEIPortInfo(portName, portInterface, features); |
| seiContext.put(spi.portName, spi); |
| ports.put(spi.portName, spi); |
| } |
| return spi; |
| } |
| |
| public SEIModel buildRuntimeModel(QName serviceName, QName portName, Class portInterface, WSDLPort wsdlPort, WebServiceFeatureList features) { |
| DatabindingFactory fac = DatabindingFactory.newInstance(); |
| DatabindingConfig config = new DatabindingConfig(); |
| config.setContractClass(portInterface); |
| config.getMappingInfo().setServiceName(serviceName); |
| config.setWsdlPort(wsdlPort); |
| config.setFeatures(features); |
| config.setClassLoader(portInterface.getClassLoader()); |
| config.getMappingInfo().setPortName(portName); |
| config.setWsdlURL(wsdlURL); |
| // if ExternalMetadataFeature present, ExternalMetadataReader will be created ... |
| config.setMetadataReader(getMetadadaReader(features, portInterface.getClassLoader())); |
| |
| com.sun.xml.internal.ws.db.DatabindingImpl rt = (com.sun.xml.internal.ws.db.DatabindingImpl)fac.createRuntime(config); |
| |
| return rt.getModel(); |
| } |
| |
| private MetadataReader getMetadadaReader(WebServiceFeatureList features, ClassLoader classLoader) { |
| if (features == null) return null; |
| com.oracle.webservices.internal.api.databinding.ExternalMetadataFeature ef = |
| features.get(com.oracle.webservices.internal.api.databinding.ExternalMetadataFeature.class); |
| // TODO-Miran: would it be necessary to disable secure xml processing? |
| if (ef != null) |
| return ef.getMetadataReader(classLoader, false); |
| return null; |
| } |
| |
| private SEIPortInfo createSEIPortInfo(QName portName, Class portInterface, WebServiceFeatureList features) { |
| WSDLPort wsdlPort = getPortModel(wsdlService, portName); |
| SEIModel model = buildRuntimeModel(serviceName, portName, portInterface, wsdlPort, features); |
| |
| return new SEIPortInfo(this, portInterface, (SOAPSEIModel) model, wsdlPort); |
| } |
| |
| private boolean useOwnSEIModel(WebServiceFeatureList features) { |
| return features.contains(UsesJAXBContextFeature.class); |
| } |
| |
| public WSDLService getWsdlService() { |
| return wsdlService; |
| } |
| |
| protected static final WebServiceFeature[] EMPTY_FEATURES = new WebServiceFeature[0]; |
| |
| private static ClassLoader getDelegatingLoader(ClassLoader loader1, ClassLoader loader2) { |
| if (loader1 == null) return loader2; |
| if (loader2 == null) return loader1; |
| return new DelegatingLoader(loader1, loader2); |
| } |
| |
| private static final class DelegatingLoader extends ClassLoader { |
| private final ClassLoader loader; |
| |
| @Override |
| public int hashCode() { |
| final int prime = 31; |
| int result = 1; |
| result = prime * result |
| + ((loader == null) ? 0 : loader.hashCode()); |
| result = prime * result |
| + ((getParent() == null) ? 0 : getParent().hashCode()); |
| return result; |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| if (this == obj) |
| return true; |
| if (obj == null) |
| return false; |
| if (getClass() != obj.getClass()) |
| return false; |
| DelegatingLoader other = (DelegatingLoader) obj; |
| if (loader == null) { |
| if (other.loader != null) |
| return false; |
| } else if (!loader.equals(other.loader)) |
| return false; |
| if (getParent() == null) { |
| if (other.getParent() != null) |
| return false; |
| } else if (!getParent().equals(other.getParent())) |
| return false; |
| return true; |
| } |
| |
| DelegatingLoader(ClassLoader loader1, ClassLoader loader2) { |
| super(loader2); |
| this.loader = loader1; |
| } |
| |
| protected Class findClass(String name) throws ClassNotFoundException { |
| return loader.loadClass(name); |
| } |
| |
| protected URL findResource(String name) { |
| return loader.getResource(name); |
| } |
| } |
| } |