aoqi@0: /* aoqi@0: * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. Oracle designates this aoqi@0: * particular file as subject to the "Classpath" exception as provided aoqi@0: * by Oracle in the LICENSE file that accompanied this code. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: */ aoqi@0: aoqi@0: package com.sun.xml.internal.ws.server; aoqi@0: aoqi@0: import com.sun.istack.internal.NotNull; aoqi@0: import com.sun.istack.internal.Nullable; aoqi@0: import com.sun.xml.internal.stream.buffer.MutableXMLStreamBuffer; aoqi@0: import com.sun.xml.internal.ws.api.BindingID; aoqi@0: import com.sun.xml.internal.ws.api.WSBinding; aoqi@0: import com.sun.xml.internal.ws.api.WSFeatureList; aoqi@0: import com.sun.xml.internal.ws.api.databinding.DatabindingConfig; aoqi@0: import com.sun.xml.internal.ws.api.databinding.DatabindingFactory; aoqi@0: import com.sun.xml.internal.ws.api.databinding.MetadataReader; aoqi@0: import com.sun.xml.internal.ws.api.databinding.WSDLGenInfo; aoqi@0: import com.sun.xml.internal.ws.api.model.SEIModel; aoqi@0: import com.sun.xml.internal.ws.api.model.wsdl.WSDLModel; aoqi@0: import com.sun.xml.internal.ws.api.model.wsdl.WSDLPort; aoqi@0: import com.sun.xml.internal.ws.api.model.wsdl.WSDLService; aoqi@0: import com.sun.xml.internal.ws.api.policy.PolicyResolver; aoqi@0: import com.sun.xml.internal.ws.api.policy.PolicyResolverFactory; aoqi@0: import com.sun.xml.internal.ws.api.server.AsyncProvider; aoqi@0: import com.sun.xml.internal.ws.api.server.Container; aoqi@0: import com.sun.xml.internal.ws.api.server.ContainerResolver; aoqi@0: import com.sun.xml.internal.ws.api.server.InstanceResolver; aoqi@0: import com.sun.xml.internal.ws.api.server.Invoker; aoqi@0: import com.sun.xml.internal.ws.api.server.SDDocument; aoqi@0: import com.sun.xml.internal.ws.api.server.SDDocumentSource; aoqi@0: import com.sun.xml.internal.ws.api.server.WSEndpoint; aoqi@0: import com.sun.xml.internal.ws.api.streaming.XMLStreamReaderFactory; aoqi@0: import com.sun.xml.internal.ws.api.wsdl.parser.WSDLParserExtension; aoqi@0: import com.sun.xml.internal.ws.api.wsdl.parser.XMLEntityResolver; aoqi@0: import com.sun.xml.internal.ws.api.wsdl.parser.XMLEntityResolver.Parser; aoqi@0: import com.sun.xml.internal.ws.api.wsdl.writer.WSDLGeneratorExtension; aoqi@0: import com.sun.xml.internal.ws.binding.BindingImpl; aoqi@0: import com.sun.xml.internal.ws.binding.SOAPBindingImpl; aoqi@0: import com.sun.xml.internal.ws.binding.WebServiceFeatureList; aoqi@0: import com.sun.xml.internal.ws.model.AbstractSEIModelImpl; aoqi@0: import com.sun.xml.internal.ws.model.ReflectAnnotationReader; aoqi@0: import com.sun.xml.internal.ws.model.RuntimeModeler; aoqi@0: import com.sun.xml.internal.ws.model.SOAPSEIModel; aoqi@0: import com.sun.xml.internal.ws.policy.PolicyMap; aoqi@0: import com.sun.xml.internal.ws.policy.jaxws.PolicyUtil; aoqi@0: import com.sun.xml.internal.ws.resources.ServerMessages; aoqi@0: import com.sun.xml.internal.ws.server.provider.ProviderInvokerTube; aoqi@0: import com.sun.xml.internal.ws.server.sei.SEIInvokerTube; aoqi@0: import com.sun.xml.internal.ws.util.HandlerAnnotationInfo; aoqi@0: import com.sun.xml.internal.ws.util.HandlerAnnotationProcessor; aoqi@0: import com.sun.xml.internal.ws.util.ServiceConfigurationError; aoqi@0: import com.sun.xml.internal.ws.util.ServiceFinder; aoqi@0: import com.sun.xml.internal.ws.util.xml.XmlUtil; aoqi@0: import com.sun.xml.internal.ws.wsdl.parser.RuntimeWSDLParser; aoqi@0: aoqi@0: import org.xml.sax.EntityResolver; aoqi@0: import org.xml.sax.InputSource; aoqi@0: import org.xml.sax.SAXException; aoqi@0: aoqi@0: import javax.jws.WebService; aoqi@0: import javax.xml.namespace.QName; aoqi@0: import javax.xml.stream.XMLStreamException; aoqi@0: import javax.xml.stream.XMLStreamReader; aoqi@0: import javax.xml.ws.Provider; aoqi@0: import javax.xml.ws.WebServiceException; aoqi@0: import javax.xml.ws.WebServiceFeature; aoqi@0: import javax.xml.ws.WebServiceProvider; aoqi@0: import javax.xml.ws.soap.SOAPBinding; aoqi@0: aoqi@0: import java.io.IOException; aoqi@0: import java.net.URL; aoqi@0: import java.util.ArrayList; aoqi@0: import java.util.Collection; aoqi@0: import java.util.HashMap; aoqi@0: import java.util.List; aoqi@0: import java.util.Map; aoqi@0: import java.util.logging.Logger; aoqi@0: aoqi@0: /** aoqi@0: * Entry point to the JAX-WS RI server-side runtime. aoqi@0: * aoqi@0: * @author Kohsuke Kawaguchi aoqi@0: * @author Jitendra Kotamraju aoqi@0: */ aoqi@0: public class EndpointFactory { aoqi@0: private static final EndpointFactory instance = new EndpointFactory(); aoqi@0: aoqi@0: public static EndpointFactory getInstance() { aoqi@0: return instance; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Implements {@link WSEndpoint#create}. aoqi@0: * aoqi@0: * No need to take WebServiceContext implementation. When InvokerPipe is aoqi@0: * instantiated, it calls InstanceResolver to set up a WebServiceContext. aoqi@0: * We shall only take delegate to getUserPrincipal and isUserInRole from adapter. aoqi@0: * aoqi@0: *

aoqi@0: * Nobody else should be calling this method. aoqi@0: */ aoqi@0: public static WSEndpoint createEndpoint( aoqi@0: Class implType, boolean processHandlerAnnotation, @Nullable Invoker invoker, aoqi@0: @Nullable QName serviceName, @Nullable QName portName, aoqi@0: @Nullable Container container, @Nullable WSBinding binding, aoqi@0: @Nullable SDDocumentSource primaryWsdl, aoqi@0: @Nullable Collection metadata, aoqi@0: EntityResolver resolver, boolean isTransportSynchronous) { aoqi@0: return createEndpoint(implType, processHandlerAnnotation, invoker, serviceName, aoqi@0: portName, container, binding, primaryWsdl, metadata, resolver, isTransportSynchronous, true); aoqi@0: } aoqi@0: aoqi@0: public static WSEndpoint createEndpoint( aoqi@0: Class implType, boolean processHandlerAnnotation, @Nullable Invoker invoker, aoqi@0: @Nullable QName serviceName, @Nullable QName portName, aoqi@0: @Nullable Container container, @Nullable WSBinding binding, aoqi@0: @Nullable SDDocumentSource primaryWsdl, aoqi@0: @Nullable Collection metadata, aoqi@0: EntityResolver resolver, boolean isTransportSynchronous, boolean isStandard) { aoqi@0: EndpointFactory factory = container != null ? container.getSPI(EndpointFactory.class) : null; aoqi@0: if (factory == null) aoqi@0: factory = EndpointFactory.getInstance(); aoqi@0: aoqi@0: return factory.create( aoqi@0: implType,processHandlerAnnotation, invoker,serviceName,portName,container,binding,primaryWsdl,metadata,resolver,isTransportSynchronous,isStandard); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Implements {@link WSEndpoint#create}. aoqi@0: * aoqi@0: * No need to take WebServiceContext implementation. When InvokerPipe is aoqi@0: * instantiated, it calls InstanceResolver to set up a WebServiceContext. aoqi@0: * We shall only take delegate to getUserPrincipal and isUserInRole from adapter. aoqi@0: * aoqi@0: *

aoqi@0: * Nobody else should be calling this method. aoqi@0: */ aoqi@0: public WSEndpoint create( aoqi@0: Class implType, boolean processHandlerAnnotation, @Nullable Invoker invoker, aoqi@0: @Nullable QName serviceName, @Nullable QName portName, aoqi@0: @Nullable Container container, @Nullable WSBinding binding, aoqi@0: @Nullable SDDocumentSource primaryWsdl, aoqi@0: @Nullable Collection metadata, aoqi@0: EntityResolver resolver, boolean isTransportSynchronous) { aoqi@0: return create(implType, processHandlerAnnotation, invoker, serviceName, aoqi@0: portName, container, binding, primaryWsdl, metadata, resolver, isTransportSynchronous, aoqi@0: true); aoqi@0: aoqi@0: } aoqi@0: aoqi@0: public WSEndpoint create( aoqi@0: Class implType, boolean processHandlerAnnotation, @Nullable Invoker invoker, aoqi@0: @Nullable QName serviceName, @Nullable QName portName, aoqi@0: @Nullable Container container, @Nullable WSBinding binding, aoqi@0: @Nullable SDDocumentSource primaryWsdl, aoqi@0: @Nullable Collection metadata, aoqi@0: EntityResolver resolver, boolean isTransportSynchronous, boolean isStandard) { aoqi@0: aoqi@0: if(implType ==null) aoqi@0: throw new IllegalArgumentException(); aoqi@0: aoqi@0: MetadataReader metadataReader = getExternalMetadatReader(implType, binding); aoqi@0: aoqi@0: if (isStandard) { aoqi@0: verifyImplementorClass(implType, metadataReader); aoqi@0: } aoqi@0: aoqi@0: if (invoker == null) { aoqi@0: invoker = InstanceResolver.createDefault(implType).createInvoker(); aoqi@0: } aoqi@0: aoqi@0: List md = new ArrayList(); aoqi@0: if(metadata!=null) aoqi@0: md.addAll(metadata); aoqi@0: aoqi@0: if(primaryWsdl!=null && !md.contains(primaryWsdl)) aoqi@0: md.add(primaryWsdl); aoqi@0: aoqi@0: if(container==null) aoqi@0: container = ContainerResolver.getInstance().getContainer(); aoqi@0: aoqi@0: if(serviceName==null) aoqi@0: serviceName = getDefaultServiceName(implType, metadataReader); aoqi@0: aoqi@0: if(portName==null) aoqi@0: portName = getDefaultPortName(serviceName,implType, metadataReader); aoqi@0: aoqi@0: {// error check aoqi@0: String serviceNS = serviceName.getNamespaceURI(); aoqi@0: String portNS = portName.getNamespaceURI(); aoqi@0: if (!serviceNS.equals(portNS)) { aoqi@0: throw new ServerRtException("wrong.tns.for.port",portNS, serviceNS); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // setting a default binding aoqi@0: if (binding == null) aoqi@0: binding = BindingImpl.create(BindingID.parse(implType)); aoqi@0: aoqi@0: if ( isStandard && primaryWsdl != null) { aoqi@0: verifyPrimaryWSDL(primaryWsdl, serviceName); aoqi@0: } aoqi@0: aoqi@0: QName portTypeName = null; aoqi@0: if (isStandard && implType.getAnnotation(WebServiceProvider.class)==null) { aoqi@0: portTypeName = RuntimeModeler.getPortTypeName(implType, metadataReader); aoqi@0: } aoqi@0: aoqi@0: // Categorises the documents as WSDL, Schema etc aoqi@0: List docList = categoriseMetadata(md, serviceName, portTypeName); aoqi@0: // Finds the primary WSDL and makes sure that metadata doesn't have aoqi@0: // two concrete or abstract WSDLs aoqi@0: SDDocumentImpl primaryDoc = primaryWsdl != null ? SDDocumentImpl.create(primaryWsdl,serviceName,portTypeName) : findPrimary(docList); aoqi@0: aoqi@0: EndpointAwareTube terminal; aoqi@0: WSDLPort wsdlPort = null; aoqi@0: AbstractSEIModelImpl seiModel = null; aoqi@0: // create WSDL model aoqi@0: if (primaryDoc != null) { aoqi@0: wsdlPort = getWSDLPort(primaryDoc, docList, serviceName, portName, container, resolver); aoqi@0: } aoqi@0: aoqi@0: WebServiceFeatureList features=((BindingImpl)binding).getFeatures(); aoqi@0: if (isStandard) { aoqi@0: features.parseAnnotations(implType); aoqi@0: } aoqi@0: PolicyMap policyMap = null; aoqi@0: // create terminal pipe that invokes the application aoqi@0: if (isUseProviderTube(implType, isStandard)) { aoqi@0: //TODO incase of Provider, provide a way to User for complete control of the message processing by giving aoqi@0: // ability to turn off the WSDL/Policy based features and its associated tubes. aoqi@0: aoqi@0: //Even in case of Provider, merge all features configured via WSDL/Policy or deployment configuration aoqi@0: Iterable configFtrs; aoqi@0: if(wsdlPort != null) { aoqi@0: policyMap = wsdlPort.getOwner().getParent().getPolicyMap(); aoqi@0: //Merge features from WSDL and other policy configuration aoqi@0: configFtrs = wsdlPort.getFeatures(); aoqi@0: } else { aoqi@0: //No WSDL, so try to merge features from Policy configuration aoqi@0: policyMap = PolicyResolverFactory.create().resolve( aoqi@0: new PolicyResolver.ServerContext(null, container, implType, false)); aoqi@0: configFtrs = PolicyUtil.getPortScopedFeatures(policyMap,serviceName,portName); aoqi@0: } aoqi@0: features.mergeFeatures(configFtrs, true); aoqi@0: terminal = createProviderInvokerTube(implType, binding, invoker, container); aoqi@0: } else { aoqi@0: // Create runtime model for non Provider endpoints aoqi@0: seiModel = createSEIModel(wsdlPort, implType, serviceName, portName, binding, primaryDoc); aoqi@0: if(binding instanceof SOAPBindingImpl){ aoqi@0: //set portKnownHeaders on Binding, so that they can be used for MU processing aoqi@0: ((SOAPBindingImpl)binding).setPortKnownHeaders( aoqi@0: ((SOAPSEIModel)seiModel).getKnownHeaders()); aoqi@0: } aoqi@0: // Generate WSDL for SEI endpoints(not for Provider endpoints) aoqi@0: if (primaryDoc == null) { aoqi@0: primaryDoc = generateWSDL(binding, seiModel, docList, container, implType); aoqi@0: // create WSDL model aoqi@0: wsdlPort = getWSDLPort(primaryDoc, docList, serviceName, portName, container, resolver); aoqi@0: seiModel.freeze(wsdlPort); aoqi@0: } aoqi@0: policyMap = wsdlPort.getOwner().getParent().getPolicyMap(); aoqi@0: // New Features might have been added in WSDL through Policy. aoqi@0: //Merge features from WSDL and other policy configuration aoqi@0: // This sets only the wsdl features that are not already set(enabled/disabled) aoqi@0: features.mergeFeatures(wsdlPort.getFeatures(), true); aoqi@0: terminal = createSEIInvokerTube(seiModel,invoker,binding); aoqi@0: } aoqi@0: aoqi@0: // Process @HandlerChain, if handler-chain is not set via Deployment Descriptor aoqi@0: if (processHandlerAnnotation) { aoqi@0: processHandlerAnnotation(binding, implType, serviceName, portName); aoqi@0: } aoqi@0: // Selects only required metadata for this endpoint from the passed-in metadata aoqi@0: if (primaryDoc != null) { aoqi@0: docList = findMetadataClosure(primaryDoc, docList, resolver); aoqi@0: } aoqi@0: aoqi@0: ServiceDefinitionImpl serviceDefiniton = (primaryDoc != null) ? new ServiceDefinitionImpl(docList, primaryDoc) : null; aoqi@0: aoqi@0: return create(serviceName, portName, binding, container, seiModel, wsdlPort, implType, serviceDefiniton, aoqi@0: terminal, isTransportSynchronous, policyMap); aoqi@0: } aoqi@0: aoqi@0: protected WSEndpoint create(QName serviceName, QName portName, WSBinding binding, Container container, SEIModel seiModel, WSDLPort wsdlPort, Class implType, ServiceDefinitionImpl serviceDefinition, EndpointAwareTube terminal, boolean isTransportSynchronous, PolicyMap policyMap) { aoqi@0: return new WSEndpointImpl(serviceName, portName, binding, container, seiModel, aoqi@0: wsdlPort, implType, serviceDefinition, terminal, isTransportSynchronous, policyMap); aoqi@0: } aoqi@0: aoqi@0: protected boolean isUseProviderTube(Class implType, boolean isStandard) { aoqi@0: return !isStandard || implType.getAnnotation(WebServiceProvider.class)!=null; aoqi@0: } aoqi@0: aoqi@0: protected EndpointAwareTube createSEIInvokerTube(AbstractSEIModelImpl seiModel, Invoker invoker, WSBinding binding) { aoqi@0: return new SEIInvokerTube(seiModel,invoker,binding); aoqi@0: } aoqi@0: aoqi@0: protected EndpointAwareTube createProviderInvokerTube(final Class implType, final WSBinding binding, aoqi@0: final Invoker invoker, final Container container) { aoqi@0: return ProviderInvokerTube.create(implType, binding, invoker, container); aoqi@0: } aoqi@0: /** aoqi@0: * Goes through the original metadata documents and collects the required ones. aoqi@0: * This done traversing from primary WSDL and its imports until it builds a aoqi@0: * complete set of documents(transitive closure) for the endpoint. aoqi@0: * aoqi@0: * @param primaryDoc primary WSDL doc aoqi@0: * @param docList complete metadata aoqi@0: * @return new metadata that doesn't contain extraneous documnets. aoqi@0: */ aoqi@0: private static List findMetadataClosure(SDDocumentImpl primaryDoc, List docList, EntityResolver resolver) { aoqi@0: // create a map for old metadata aoqi@0: Map oldMap = new HashMap(); aoqi@0: for(SDDocumentImpl doc : docList) { aoqi@0: oldMap.put(doc.getSystemId().toString(), doc); aoqi@0: } aoqi@0: // create a map for new metadata aoqi@0: Map newMap = new HashMap(); aoqi@0: newMap.put(primaryDoc.getSystemId().toString(), primaryDoc); aoqi@0: aoqi@0: List remaining = new ArrayList(); aoqi@0: remaining.addAll(primaryDoc.getImports()); aoqi@0: while(!remaining.isEmpty()) { aoqi@0: String url = remaining.remove(0); aoqi@0: SDDocumentImpl doc = oldMap.get(url); aoqi@0: if (doc == null) { aoqi@0: // old metadata doesn't have this imported doc, may be external aoqi@0: if (resolver != null) { aoqi@0: try { aoqi@0: InputSource source = resolver.resolveEntity(null, url); aoqi@0: if (source != null) { aoqi@0: MutableXMLStreamBuffer xsb = new MutableXMLStreamBuffer(); aoqi@0: XMLStreamReader reader = XmlUtil.newXMLInputFactory(true).createXMLStreamReader(source.getByteStream()); aoqi@0: xsb.createFromXMLStreamReader(reader); aoqi@0: aoqi@0: SDDocumentSource sdocSource = SDDocumentImpl.create(new URL(url), xsb); aoqi@0: doc = SDDocumentImpl.create(sdocSource, null, null); aoqi@0: } aoqi@0: } catch (Exception ex) { aoqi@0: ex.printStackTrace(); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: // Check if new metadata already contains this doc aoqi@0: if (doc != null && !newMap.containsKey(url)) { aoqi@0: newMap.put(url, doc); aoqi@0: remaining.addAll(doc.getImports()); aoqi@0: } aoqi@0: } aoqi@0: List newMetadata = new ArrayList(); aoqi@0: newMetadata.addAll(newMap.values()); aoqi@0: return newMetadata; aoqi@0: } aoqi@0: aoqi@0: private static void processHandlerAnnotation(WSBinding binding, Class implType, QName serviceName, QName portName) { aoqi@0: HandlerAnnotationInfo chainInfo = aoqi@0: HandlerAnnotationProcessor.buildHandlerInfo( aoqi@0: implType, serviceName, portName, binding); aoqi@0: if (chainInfo != null) { aoqi@0: binding.setHandlerChain(chainInfo.getHandlers()); aoqi@0: if (binding instanceof SOAPBinding) { aoqi@0: ((SOAPBinding) binding).setRoles(chainInfo.getRoles()); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Verifies if the endpoint implementor class has @WebService or @WebServiceProvider aoqi@0: * annotation aoqi@0: * aoqi@0: * @return aoqi@0: * true if it is a Provider or AsyncProvider endpoint aoqi@0: * false otherwise aoqi@0: * @throws java.lang.IllegalArgumentException aoqi@0: * If it doesn't have any one of @WebService or @WebServiceProvider aoqi@0: * If it has both @WebService and @WebServiceProvider annotations aoqi@0: */ aoqi@0: public static boolean verifyImplementorClass(Class clz) { aoqi@0: return verifyImplementorClass(clz, null); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Verifies if the endpoint implementor class has @WebService or @WebServiceProvider aoqi@0: * annotation; passing MetadataReader instance allows to read annotations from aoqi@0: * xml descriptor instead of class's annotations aoqi@0: * aoqi@0: * @return aoqi@0: * true if it is a Provider or AsyncProvider endpoint aoqi@0: * false otherwise aoqi@0: * @throws java.lang.IllegalArgumentException aoqi@0: * If it doesn't have any one of @WebService or @WebServiceProvider aoqi@0: * If it has both @WebService and @WebServiceProvider annotations aoqi@0: */ aoqi@0: public static boolean verifyImplementorClass(Class clz, MetadataReader metadataReader) { aoqi@0: aoqi@0: if (metadataReader == null) { aoqi@0: metadataReader = new ReflectAnnotationReader(); aoqi@0: } aoqi@0: aoqi@0: WebServiceProvider wsProvider = metadataReader.getAnnotation(WebServiceProvider.class, clz); aoqi@0: WebService ws = metadataReader.getAnnotation(WebService.class, clz); aoqi@0: if (wsProvider == null && ws == null) { aoqi@0: throw new IllegalArgumentException(clz +" has neither @WebService nor @WebServiceProvider annotation"); aoqi@0: } aoqi@0: if (wsProvider != null && ws != null) { aoqi@0: throw new IllegalArgumentException(clz +" has both @WebService and @WebServiceProvider annotations"); aoqi@0: } aoqi@0: if (wsProvider != null) { aoqi@0: if (Provider.class.isAssignableFrom(clz) || AsyncProvider.class.isAssignableFrom(clz)) { aoqi@0: return true; aoqi@0: } aoqi@0: throw new IllegalArgumentException(clz +" doesn't implement Provider or AsyncProvider interface"); aoqi@0: } aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: private static AbstractSEIModelImpl createSEIModel(WSDLPort wsdlPort, aoqi@0: Class implType, @NotNull QName serviceName, @NotNull QName portName, WSBinding binding, aoqi@0: SDDocumentSource primaryWsdl) { aoqi@0: DatabindingFactory fac = DatabindingFactory.newInstance(); aoqi@0: DatabindingConfig config = new DatabindingConfig(); aoqi@0: config.setEndpointClass(implType); aoqi@0: config.getMappingInfo().setServiceName(serviceName); aoqi@0: config.setWsdlPort(wsdlPort); aoqi@0: config.setWSBinding(binding); aoqi@0: config.setClassLoader(implType.getClassLoader()); aoqi@0: config.getMappingInfo().setPortName(portName); aoqi@0: if (primaryWsdl != null) config.setWsdlURL(primaryWsdl.getSystemId()); aoqi@0: config.setMetadataReader(getExternalMetadatReader(implType, binding)); aoqi@0: aoqi@0: com.sun.xml.internal.ws.db.DatabindingImpl rt = (com.sun.xml.internal.ws.db.DatabindingImpl)fac.createRuntime(config); aoqi@0: return (AbstractSEIModelImpl) rt.getModel(); aoqi@0: } aoqi@0: aoqi@0: public static MetadataReader getExternalMetadatReader(Class implType, WSBinding binding) { aoqi@0: com.oracle.webservices.internal.api.databinding.ExternalMetadataFeature ef = binding.getFeature( aoqi@0: com.oracle.webservices.internal.api.databinding.ExternalMetadataFeature.class); aoqi@0: // TODO-Miran: would it be necessary to disable secure xml processing? aoqi@0: if (ef != null) aoqi@0: return ef.getMetadataReader(implType.getClassLoader(), false); aoqi@0: return null; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: *Set the mtom enable setting from wsdl model (mtom policy assertion) on to @link WSBinding} if DD has aoqi@0: * not already set it on BindingID. Also check conflicts. aoqi@0: */ aoqi@0: /* aoqi@0: private static void applyEffectiveMtomSetting(WSDLBoundPortType wsdlBinding, WSBinding binding){ aoqi@0: if(wsdlBinding.isMTOMEnabled()){ aoqi@0: BindingID bindingId = binding.getBindingId(); aoqi@0: if(bindingId.isMTOMEnabled() == null){ aoqi@0: binding.setMTOMEnabled(true); aoqi@0: }else if (bindingId.isMTOMEnabled() != null && bindingId.isMTOMEnabled() == Boolean.FALSE){ aoqi@0: //TODO: i18N aoqi@0: throw new ServerRtException("Deployment failed! Mtom policy assertion in WSDL is enabled whereas the deplyment descriptor setting wants to disable it!"); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: */ aoqi@0: /** aoqi@0: * If service name is not already set via DD or programmatically, it uses aoqi@0: * annotations {@link WebServiceProvider}, {@link WebService} on implementorClass to get PortName. aoqi@0: * aoqi@0: * @return non-null service name aoqi@0: */ aoqi@0: public static @NotNull QName getDefaultServiceName(Class implType) { aoqi@0: return getDefaultServiceName(implType, null); aoqi@0: } aoqi@0: aoqi@0: public static @NotNull QName getDefaultServiceName(Class implType, MetadataReader metadataReader) { aoqi@0: return getDefaultServiceName(implType, true, metadataReader); aoqi@0: } aoqi@0: aoqi@0: public static @NotNull QName getDefaultServiceName(Class implType, boolean isStandard) { aoqi@0: return getDefaultServiceName(implType, isStandard, null); aoqi@0: } aoqi@0: aoqi@0: public static @NotNull QName getDefaultServiceName(Class implType, boolean isStandard, MetadataReader metadataReader) { aoqi@0: if (metadataReader == null) { aoqi@0: metadataReader = new ReflectAnnotationReader(); aoqi@0: } aoqi@0: QName serviceName; aoqi@0: WebServiceProvider wsProvider = metadataReader.getAnnotation(WebServiceProvider.class, implType); aoqi@0: if (wsProvider!=null) { aoqi@0: String tns = wsProvider.targetNamespace(); aoqi@0: String local = wsProvider.serviceName(); aoqi@0: serviceName = new QName(tns, local); aoqi@0: } else { aoqi@0: serviceName = RuntimeModeler.getServiceName(implType, metadataReader, isStandard); aoqi@0: } aoqi@0: assert serviceName != null; aoqi@0: return serviceName; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * If portName is not already set via DD or programmatically, it uses aoqi@0: * annotations on implementorClass to get PortName. aoqi@0: * aoqi@0: * @return non-null port name aoqi@0: */ aoqi@0: public static @NotNull QName getDefaultPortName(QName serviceName, Class implType) { aoqi@0: return getDefaultPortName(serviceName, implType, null); aoqi@0: } aoqi@0: aoqi@0: public static @NotNull QName getDefaultPortName(QName serviceName, Class implType, MetadataReader metadataReader) { aoqi@0: return getDefaultPortName(serviceName, implType, true, metadataReader); aoqi@0: } aoqi@0: aoqi@0: public static @NotNull QName getDefaultPortName(QName serviceName, Class implType, boolean isStandard) { aoqi@0: return getDefaultPortName(serviceName, implType, isStandard, null); aoqi@0: } aoqi@0: aoqi@0: public static @NotNull QName getDefaultPortName(QName serviceName, Class implType, boolean isStandard, MetadataReader metadataReader) { aoqi@0: if (metadataReader == null) { aoqi@0: metadataReader = new ReflectAnnotationReader(); aoqi@0: } aoqi@0: QName portName; aoqi@0: WebServiceProvider wsProvider = metadataReader.getAnnotation(WebServiceProvider.class, implType); aoqi@0: if (wsProvider!=null) { aoqi@0: String tns = wsProvider.targetNamespace(); aoqi@0: String local = wsProvider.portName(); aoqi@0: portName = new QName(tns, local); aoqi@0: } else { aoqi@0: portName = RuntimeModeler.getPortName(implType, metadataReader, serviceName.getNamespaceURI(), isStandard); aoqi@0: } aoqi@0: assert portName != null; aoqi@0: return portName; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Returns the wsdl from @WebService, or @WebServiceProvider annotation using aoqi@0: * wsdlLocation element. aoqi@0: * aoqi@0: * @param implType aoqi@0: * endpoint implementation class aoqi@0: * make sure that you called {@link #verifyImplementorClass} on it. aoqi@0: * @return wsdl if there is wsdlLocation, else null aoqi@0: */ aoqi@0: public static @Nullable String getWsdlLocation(Class implType) { aoqi@0: return getWsdlLocation(implType, new ReflectAnnotationReader()); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Returns the wsdl from @WebService, or @WebServiceProvider annotation using aoqi@0: * wsdlLocation element. aoqi@0: * aoqi@0: * @param implType aoqi@0: * endpoint implementation class aoqi@0: * make sure that you called {@link #verifyImplementorClass} on it. aoqi@0: * @return wsdl if there is wsdlLocation, else null aoqi@0: */ aoqi@0: public static @Nullable String getWsdlLocation(Class implType, MetadataReader metadataReader) { aoqi@0: aoqi@0: if (metadataReader == null) { aoqi@0: metadataReader = new ReflectAnnotationReader(); aoqi@0: } aoqi@0: aoqi@0: WebService ws = metadataReader.getAnnotation(WebService.class, implType); aoqi@0: if (ws != null) { aoqi@0: return nullIfEmpty(ws.wsdlLocation()); aoqi@0: } else { aoqi@0: WebServiceProvider wsProvider = implType.getAnnotation(WebServiceProvider.class); aoqi@0: assert wsProvider != null; aoqi@0: return nullIfEmpty(wsProvider.wsdlLocation()); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: private static String nullIfEmpty(String string) { aoqi@0: if (string.length() < 1) { aoqi@0: string = null; aoqi@0: } aoqi@0: return string; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Generates the WSDL and XML Schema for the endpoint if necessary aoqi@0: * It generates WSDL only for SOAP1.1, and for XSOAP1.2 bindings aoqi@0: */ aoqi@0: private static SDDocumentImpl generateWSDL(WSBinding binding, AbstractSEIModelImpl seiModel, List docs, aoqi@0: Container container, Class implType) { aoqi@0: BindingID bindingId = binding.getBindingId(); aoqi@0: if (!bindingId.canGenerateWSDL()) { aoqi@0: throw new ServerRtException("can.not.generate.wsdl", bindingId); aoqi@0: } aoqi@0: aoqi@0: if (bindingId.toString().equals(SOAPBindingImpl.X_SOAP12HTTP_BINDING)) { aoqi@0: String msg = ServerMessages.GENERATE_NON_STANDARD_WSDL(); aoqi@0: logger.warning(msg); aoqi@0: } aoqi@0: aoqi@0: // Generate WSDL and schema documents using runtime model aoqi@0: WSDLGenResolver wsdlResolver = new WSDLGenResolver(docs,seiModel.getServiceQName(),seiModel.getPortTypeName()); aoqi@0: WSDLGenInfo wsdlGenInfo = new WSDLGenInfo(); aoqi@0: wsdlGenInfo.setWsdlResolver(wsdlResolver); aoqi@0: wsdlGenInfo.setContainer(container); aoqi@0: wsdlGenInfo.setExtensions(ServiceFinder.find(WSDLGeneratorExtension.class).toArray()); aoqi@0: wsdlGenInfo.setInlineSchemas(false); aoqi@0: wsdlGenInfo.setSecureXmlProcessingDisabled(isSecureXmlProcessingDisabled(binding.getFeatures())); aoqi@0: seiModel.getDatabinding().generateWSDL(wsdlGenInfo); aoqi@0: // WSDLGenerator wsdlGen = new WSDLGenerator(seiModel, wsdlResolver, binding, container, implType, false, aoqi@0: // ServiceFinder.find(WSDLGeneratorExtension.class).toArray()); aoqi@0: // wsdlGen.doGeneration(); aoqi@0: return wsdlResolver.updateDocs(); aoqi@0: } aoqi@0: aoqi@0: private static boolean isSecureXmlProcessingDisabled(WSFeatureList featureList) { aoqi@0: // TODO-Miran: would it be necessary to disable secure xml processing? aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Builds {@link SDDocumentImpl} from {@link SDDocumentSource}. aoqi@0: */ aoqi@0: private static List categoriseMetadata( aoqi@0: List src, QName serviceName, QName portTypeName) { aoqi@0: aoqi@0: List r = new ArrayList(src.size()); aoqi@0: for (SDDocumentSource doc : src) { aoqi@0: r.add(SDDocumentImpl.create(doc,serviceName,portTypeName)); aoqi@0: } aoqi@0: return r; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Verifies whether the given primaryWsdl contains the given serviceName. aoqi@0: * If the WSDL doesn't have the service, it throws an WebServiceException. aoqi@0: */ aoqi@0: private static void verifyPrimaryWSDL(@NotNull SDDocumentSource primaryWsdl, @NotNull QName serviceName) { aoqi@0: SDDocumentImpl primaryDoc = SDDocumentImpl.create(primaryWsdl,serviceName,null); aoqi@0: if (!(primaryDoc instanceof SDDocument.WSDL)) { aoqi@0: throw new WebServiceException(primaryWsdl.getSystemId()+ aoqi@0: " is not a WSDL. But it is passed as a primary WSDL"); aoqi@0: } aoqi@0: SDDocument.WSDL wsdlDoc = (SDDocument.WSDL)primaryDoc; aoqi@0: if (!wsdlDoc.hasService()) { aoqi@0: if(wsdlDoc.getAllServices().isEmpty()) aoqi@0: throw new WebServiceException("Not a primary WSDL="+primaryWsdl.getSystemId()+ aoqi@0: " since it doesn't have Service "+serviceName); aoqi@0: else aoqi@0: throw new WebServiceException("WSDL "+primaryDoc.getSystemId() aoqi@0: +" has the following services "+wsdlDoc.getAllServices() aoqi@0: +" but not "+serviceName+". Maybe you forgot to specify a serviceName and/or targetNamespace in @WebService/@WebServiceProvider?"); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Finds the primary WSDL document from the list of metadata documents. If aoqi@0: * there are two metadata documents that qualify for primary, it throws an aoqi@0: * exception. If there are two metadata documents that qualify for porttype, aoqi@0: * it throws an exception. aoqi@0: * aoqi@0: * @return primay wsdl document, null if is not there in the docList aoqi@0: * aoqi@0: */ aoqi@0: private static @Nullable SDDocumentImpl findPrimary(@NotNull List docList) { aoqi@0: SDDocumentImpl primaryDoc = null; aoqi@0: boolean foundConcrete = false; aoqi@0: boolean foundAbstract = false; aoqi@0: for(SDDocumentImpl doc : docList) { aoqi@0: if (doc instanceof SDDocument.WSDL) { aoqi@0: SDDocument.WSDL wsdlDoc = (SDDocument.WSDL)doc; aoqi@0: if (wsdlDoc.hasService()) { aoqi@0: primaryDoc = doc; aoqi@0: if (foundConcrete) { aoqi@0: throw new ServerRtException("duplicate.primary.wsdl", doc.getSystemId() ); aoqi@0: } aoqi@0: foundConcrete = true; aoqi@0: } aoqi@0: if (wsdlDoc.hasPortType()) { aoqi@0: if (foundAbstract) { aoqi@0: throw new ServerRtException("duplicate.abstract.wsdl", doc.getSystemId()); aoqi@0: } aoqi@0: foundAbstract = true; aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: return primaryDoc; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Parses the primary WSDL and returns the {@link WSDLPort} for the given service and port names aoqi@0: * aoqi@0: * @param primaryWsdl Primary WSDL aoqi@0: * @param metadata it may contain imported WSDL and schema documents aoqi@0: * @param serviceName service name in wsdl aoqi@0: * @param portName port name in WSDL aoqi@0: * @param container container in which this service is running aoqi@0: * @return non-null wsdl port object aoqi@0: */ aoqi@0: private static @NotNull WSDLPort getWSDLPort(SDDocumentSource primaryWsdl, List metadata, aoqi@0: @NotNull QName serviceName, @NotNull QName portName, Container container, aoqi@0: EntityResolver resolver) { aoqi@0: URL wsdlUrl = primaryWsdl.getSystemId(); aoqi@0: try { aoqi@0: // TODO: delegate to another entity resolver aoqi@0: WSDLModel wsdlDoc = RuntimeWSDLParser.parse( aoqi@0: new Parser(primaryWsdl), new EntityResolverImpl(metadata, resolver), aoqi@0: false, container, ServiceFinder.find(WSDLParserExtension.class).toArray()); aoqi@0: if(wsdlDoc.getServices().size() == 0) { aoqi@0: throw new ServerRtException(ServerMessages.localizableRUNTIME_PARSER_WSDL_NOSERVICE_IN_WSDLMODEL(wsdlUrl)); aoqi@0: } aoqi@0: WSDLService wsdlService = wsdlDoc.getService(serviceName); aoqi@0: if (wsdlService == null) { aoqi@0: throw new ServerRtException(ServerMessages.localizableRUNTIME_PARSER_WSDL_INCORRECTSERVICE(serviceName,wsdlUrl)); aoqi@0: } aoqi@0: WSDLPort wsdlPort = wsdlService.get(portName); aoqi@0: if (wsdlPort == null) { aoqi@0: throw new ServerRtException(ServerMessages.localizableRUNTIME_PARSER_WSDL_INCORRECTSERVICEPORT(serviceName, portName, wsdlUrl)); aoqi@0: } aoqi@0: return wsdlPort; aoqi@0: } catch (IOException e) { aoqi@0: throw new ServerRtException("runtime.parser.wsdl", wsdlUrl,e); aoqi@0: } catch (XMLStreamException e) { aoqi@0: throw new ServerRtException("runtime.saxparser.exception", e.getMessage(), e.getLocation(), e); aoqi@0: } catch (SAXException e) { aoqi@0: throw new ServerRtException("runtime.parser.wsdl", wsdlUrl,e); aoqi@0: } catch (ServiceConfigurationError e) { aoqi@0: throw new ServerRtException("runtime.parser.wsdl", wsdlUrl,e); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * {@link XMLEntityResolver} that can resolve to {@link SDDocumentSource}s. aoqi@0: */ aoqi@0: private static final class EntityResolverImpl implements XMLEntityResolver { aoqi@0: private Map metadata = new HashMap(); aoqi@0: private EntityResolver resolver; aoqi@0: aoqi@0: public EntityResolverImpl(List metadata, EntityResolver resolver) { aoqi@0: for (SDDocumentSource doc : metadata) { aoqi@0: this.metadata.put(doc.getSystemId().toExternalForm(),doc); aoqi@0: } aoqi@0: this.resolver = resolver; aoqi@0: } aoqi@0: aoqi@0: public Parser resolveEntity (String publicId, String systemId) throws IOException, XMLStreamException { aoqi@0: if (systemId != null) { aoqi@0: SDDocumentSource doc = metadata.get(systemId); aoqi@0: if (doc != null) aoqi@0: return new Parser(doc); aoqi@0: } aoqi@0: if (resolver != null) { aoqi@0: try { aoqi@0: InputSource source = resolver.resolveEntity(publicId, systemId); aoqi@0: if (source != null) { aoqi@0: Parser p = new Parser(null, XMLStreamReaderFactory.create(source, true)); aoqi@0: return p; aoqi@0: } aoqi@0: } catch (SAXException e) { aoqi@0: throw new XMLStreamException(e); aoqi@0: } aoqi@0: } aoqi@0: return null; aoqi@0: } aoqi@0: aoqi@0: } aoqi@0: aoqi@0: private static final Logger logger = Logger.getLogger( aoqi@0: com.sun.xml.internal.ws.util.Constants.LoggingDomain + ".server.endpoint"); aoqi@0: }