1 /*
   2  * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.xml.internal.ws.server;
  27 
  28 import com.sun.istack.internal.NotNull;
  29 import com.sun.istack.internal.Nullable;
  30 import com.sun.xml.internal.stream.buffer.MutableXMLStreamBuffer;
  31 import com.sun.xml.internal.ws.api.BindingID;
  32 import com.sun.xml.internal.ws.api.WSBinding;
  33 import com.sun.xml.internal.ws.api.WSFeatureList;
  34 import com.sun.xml.internal.ws.api.databinding.DatabindingConfig;
  35 import com.sun.xml.internal.ws.api.databinding.DatabindingFactory;
  36 import com.sun.xml.internal.ws.api.databinding.MetadataReader;
  37 import com.sun.xml.internal.ws.api.databinding.WSDLGenInfo;
  38 import com.sun.xml.internal.ws.api.model.SEIModel;
  39 import com.sun.xml.internal.ws.api.model.wsdl.WSDLModel;
  40 import com.sun.xml.internal.ws.api.model.wsdl.WSDLPort;
  41 import com.sun.xml.internal.ws.api.model.wsdl.WSDLService;
  42 import com.sun.xml.internal.ws.api.policy.PolicyResolver;
  43 import com.sun.xml.internal.ws.api.policy.PolicyResolverFactory;
  44 import com.sun.xml.internal.ws.api.server.AsyncProvider;
  45 import com.sun.xml.internal.ws.api.server.Container;
  46 import com.sun.xml.internal.ws.api.server.ContainerResolver;
  47 import com.sun.xml.internal.ws.api.server.InstanceResolver;
  48 import com.sun.xml.internal.ws.api.server.Invoker;
  49 import com.sun.xml.internal.ws.api.server.SDDocument;
  50 import com.sun.xml.internal.ws.api.server.SDDocumentSource;
  51 import com.sun.xml.internal.ws.api.server.WSEndpoint;
  52 import com.sun.xml.internal.ws.api.streaming.XMLStreamReaderFactory;
  53 import com.sun.xml.internal.ws.api.wsdl.parser.WSDLParserExtension;
  54 import com.sun.xml.internal.ws.api.wsdl.parser.XMLEntityResolver;
  55 import com.sun.xml.internal.ws.api.wsdl.parser.XMLEntityResolver.Parser;
  56 import com.sun.xml.internal.ws.api.wsdl.writer.WSDLGeneratorExtension;
  57 import com.sun.xml.internal.ws.binding.BindingImpl;
  58 import com.sun.xml.internal.ws.binding.SOAPBindingImpl;
  59 import com.sun.xml.internal.ws.binding.WebServiceFeatureList;
  60 import com.sun.xml.internal.ws.model.AbstractSEIModelImpl;
  61 import com.sun.xml.internal.ws.model.ReflectAnnotationReader;
  62 import com.sun.xml.internal.ws.model.RuntimeModeler;
  63 import com.sun.xml.internal.ws.model.SOAPSEIModel;
  64 import com.sun.xml.internal.ws.policy.PolicyMap;
  65 import com.sun.xml.internal.ws.policy.jaxws.PolicyUtil;
  66 import com.sun.xml.internal.ws.resources.ServerMessages;
  67 import com.sun.xml.internal.ws.server.provider.ProviderInvokerTube;
  68 import com.sun.xml.internal.ws.server.sei.SEIInvokerTube;
  69 import com.sun.xml.internal.ws.util.HandlerAnnotationInfo;
  70 import com.sun.xml.internal.ws.util.HandlerAnnotationProcessor;
  71 import com.sun.xml.internal.ws.util.ServiceConfigurationError;
  72 import com.sun.xml.internal.ws.util.ServiceFinder;
  73 import com.sun.xml.internal.ws.util.xml.XmlUtil;
  74 import com.sun.xml.internal.ws.wsdl.parser.RuntimeWSDLParser;
  75 
  76 import org.xml.sax.EntityResolver;
  77 import org.xml.sax.InputSource;
  78 import org.xml.sax.SAXException;
  79 
  80 import javax.jws.WebService;
  81 import javax.xml.namespace.QName;
  82 import javax.xml.stream.XMLStreamException;
  83 import javax.xml.stream.XMLStreamReader;
  84 import javax.xml.ws.Provider;
  85 import javax.xml.ws.WebServiceException;
  86 import javax.xml.ws.WebServiceFeature;
  87 import javax.xml.ws.WebServiceProvider;
  88 import javax.xml.ws.soap.SOAPBinding;
  89 
  90 import java.io.IOException;
  91 import java.net.URL;
  92 import java.util.AbstractCollection;
  93 import java.util.ArrayList;
  94 import java.util.Collection;
  95 import java.util.Collections;
  96 import java.util.HashMap;
  97 import java.util.Iterator;
  98 import java.util.List;
  99 import java.util.Map;
 100 import java.util.NoSuchElementException;
 101 import java.util.concurrent.ConcurrentHashMap;
 102 import java.util.logging.Logger;
 103 
 104 /**
 105  * Entry point to the JAX-WS RI server-side runtime.
 106  *
 107  * @author Kohsuke Kawaguchi
 108  * @author Jitendra Kotamraju
 109  */
 110 public class EndpointFactory {
 111         private static final EndpointFactory instance = new EndpointFactory();
 112 
 113         public static EndpointFactory getInstance() {
 114                 return instance;
 115         }
 116 
 117     /**
 118      * Implements {@link WSEndpoint#create}.
 119      *
 120      * No need to take WebServiceContext implementation. When InvokerPipe is
 121      * instantiated, it calls InstanceResolver to set up a WebServiceContext.
 122      * We shall only take delegate to getUserPrincipal and isUserInRole from adapter.
 123      *
 124      * <p>
 125      * Nobody else should be calling this method.
 126      */
 127     public static <T> WSEndpoint<T> createEndpoint(
 128         Class<T> implType, boolean processHandlerAnnotation, @Nullable Invoker invoker,
 129         @Nullable QName serviceName, @Nullable QName portName,
 130         @Nullable Container container, @Nullable WSBinding binding,
 131         @Nullable SDDocumentSource primaryWsdl,
 132         @Nullable Collection<? extends SDDocumentSource> metadata,
 133         EntityResolver resolver, boolean isTransportSynchronous) {
 134         return createEndpoint(implType, processHandlerAnnotation, invoker, serviceName,
 135                         portName, container, binding, primaryWsdl, metadata, resolver, isTransportSynchronous, true);
 136     }
 137 
 138     public static <T> WSEndpoint<T> createEndpoint(
 139             Class<T> implType, boolean processHandlerAnnotation, @Nullable Invoker invoker,
 140             @Nullable QName serviceName, @Nullable QName portName,
 141             @Nullable Container container, @Nullable WSBinding binding,
 142             @Nullable SDDocumentSource primaryWsdl,
 143             @Nullable Collection<? extends SDDocumentSource> metadata,
 144             EntityResolver resolver, boolean isTransportSynchronous, boolean isStandard) {
 145         EndpointFactory factory = container != null ? container.getSPI(EndpointFactory.class) : null;
 146         if (factory == null)
 147                 factory = EndpointFactory.getInstance();
 148 
 149         return factory.create(
 150                 implType,processHandlerAnnotation, invoker,serviceName,portName,container,binding,primaryWsdl,metadata,resolver,isTransportSynchronous,isStandard);
 151     }
 152 
 153     /**
 154      * Implements {@link WSEndpoint#create}.
 155      *
 156      * No need to take WebServiceContext implementation. When InvokerPipe is
 157      * instantiated, it calls InstanceResolver to set up a WebServiceContext.
 158      * We shall only take delegate to getUserPrincipal and isUserInRole from adapter.
 159      *
 160      * <p>
 161      * Nobody else should be calling this method.
 162      */
 163     public <T> WSEndpoint<T> create(
 164             Class<T> implType, boolean processHandlerAnnotation, @Nullable Invoker invoker,
 165             @Nullable QName serviceName, @Nullable QName portName,
 166             @Nullable Container container, @Nullable WSBinding binding,
 167             @Nullable SDDocumentSource primaryWsdl,
 168             @Nullable Collection<? extends SDDocumentSource> metadata,
 169             EntityResolver resolver, boolean isTransportSynchronous) {
 170         return create(implType, processHandlerAnnotation, invoker, serviceName,
 171                         portName, container, binding, primaryWsdl, metadata, resolver, isTransportSynchronous,
 172                         true);
 173 
 174     }
 175 
 176     public <T> WSEndpoint<T> create(
 177         Class<T> implType, boolean processHandlerAnnotation, @Nullable Invoker invoker,
 178         @Nullable QName serviceName, @Nullable QName portName,
 179         @Nullable Container container, @Nullable WSBinding binding,
 180         @Nullable SDDocumentSource primaryWsdl,
 181         @Nullable Collection<? extends SDDocumentSource> metadata,
 182         EntityResolver resolver, boolean isTransportSynchronous, boolean isStandard) {
 183 
 184         if(implType ==null)
 185             throw new IllegalArgumentException();
 186 
 187         MetadataReader metadataReader = getExternalMetadatReader(implType, binding);
 188 
 189         if (isStandard) {
 190             verifyImplementorClass(implType, metadataReader);
 191         }
 192 
 193         if (invoker == null) {
 194             invoker = InstanceResolver.createDefault(implType).createInvoker();
 195         }
 196 
 197         // Performance analysis indicates that reading and parsing imported schemas is
 198         // a major component of Endpoint creation time.  Therefore, modify SDDocumentSource
 199         // handling to delay iterating collection as long as possible.
 200         Collection<SDDocumentSource> md = new CollectionCollection<SDDocumentSource>();
 201         if(primaryWsdl!=null) {
 202             if(metadata!=null) {
 203                 Iterator<? extends SDDocumentSource> it = metadata.iterator();
 204                 if (it.hasNext() && primaryWsdl.equals(it.next()))
 205                     md.addAll(metadata);
 206                 else {
 207                     md.add(primaryWsdl);
 208                     md.addAll(metadata);
 209                 }
 210             } else
 211                 md.add(primaryWsdl);
 212         } else if(metadata!=null)
 213             md.addAll(metadata);
 214 
 215         if(container==null)
 216             container = ContainerResolver.getInstance().getContainer();
 217 
 218         if(serviceName==null)
 219             serviceName = getDefaultServiceName(implType, metadataReader);
 220 
 221         if(portName==null)
 222             portName = getDefaultPortName(serviceName,implType, metadataReader);
 223 
 224         {// error check
 225             String serviceNS = serviceName.getNamespaceURI();
 226             String portNS = portName.getNamespaceURI();
 227             if (!serviceNS.equals(portNS)) {
 228                 throw new ServerRtException("wrong.tns.for.port",portNS, serviceNS);
 229             }
 230         }
 231 
 232         // setting a default binding
 233         if (binding == null)
 234             binding = BindingImpl.create(BindingID.parse(implType));
 235 
 236         if ( isStandard && primaryWsdl != null) {
 237             verifyPrimaryWSDL(primaryWsdl, serviceName);
 238         }
 239 
 240         QName portTypeName = null;
 241         if (isStandard && implType.getAnnotation(WebServiceProvider.class)==null) {
 242             portTypeName = RuntimeModeler.getPortTypeName(implType, metadataReader);
 243         }
 244 
 245         // Categorises the documents as WSDL, Schema etc
 246         Collection<SDDocumentImpl> docList = categoriseMetadata(md.iterator(), serviceName, portTypeName);
 247         // Finds the primary WSDL and makes sure that metadata doesn't have
 248         // two concrete or abstract WSDLs
 249         SDDocumentImpl primaryDoc = primaryWsdl != null ? SDDocumentImpl.create(primaryWsdl,serviceName,portTypeName) : findPrimary(docList);
 250 
 251         EndpointAwareTube terminal;
 252         WSDLPort wsdlPort = null;
 253         AbstractSEIModelImpl seiModel = null;
 254         // create WSDL model
 255         if (primaryDoc != null) {
 256             wsdlPort = getWSDLPort(primaryDoc, docList, serviceName, portName, container, resolver);
 257         }
 258 
 259         WebServiceFeatureList features=((BindingImpl)binding).getFeatures();
 260         if (isStandard) {
 261                 features.parseAnnotations(implType);
 262         }
 263         PolicyMap policyMap = null;
 264         // create terminal pipe that invokes the application
 265         if (isUseProviderTube(implType, isStandard)) {
 266             //TODO incase of Provider, provide a way to User for complete control of the message processing by giving
 267             // ability to turn off the WSDL/Policy based features and its associated tubes.
 268 
 269             //Even in case of Provider, merge all features configured via WSDL/Policy or deployment configuration
 270             Iterable<WebServiceFeature> configFtrs;
 271             if(wsdlPort != null) {
 272                  policyMap = wsdlPort.getOwner().getParent().getPolicyMap();
 273                  //Merge features from WSDL and other policy configuration
 274                 configFtrs = wsdlPort.getFeatures();
 275             } else {
 276                 //No WSDL, so try to merge features from Policy configuration
 277                 policyMap = PolicyResolverFactory.create().resolve(
 278                         new PolicyResolver.ServerContext(null, container, implType, false));
 279                 configFtrs = PolicyUtil.getPortScopedFeatures(policyMap,serviceName,portName);
 280             }
 281             features.mergeFeatures(configFtrs, true);
 282             terminal = createProviderInvokerTube(implType, binding, invoker, container);
 283         } else {
 284             // Create runtime model for non Provider endpoints
 285             seiModel = createSEIModel(wsdlPort, implType, serviceName, portName, binding, primaryDoc);
 286             if(binding instanceof SOAPBindingImpl){
 287                 //set portKnownHeaders on Binding, so that they can be used for MU processing
 288                 ((SOAPBindingImpl)binding).setPortKnownHeaders(
 289                         ((SOAPSEIModel)seiModel).getKnownHeaders());
 290             }
 291             // Generate WSDL for SEI endpoints(not for Provider endpoints)
 292             if (primaryDoc == null) {
 293                 primaryDoc = generateWSDL(binding, seiModel, docList, container, implType);
 294                 // create WSDL model
 295                 wsdlPort = getWSDLPort(primaryDoc, docList, serviceName, portName, container, resolver);
 296                 seiModel.freeze(wsdlPort);
 297             }
 298             policyMap = wsdlPort.getOwner().getParent().getPolicyMap();
 299             // New Features might have been added in WSDL through Policy.
 300             //Merge features from WSDL and other policy configuration
 301             // This sets only the wsdl features that are not already set(enabled/disabled)
 302             features.mergeFeatures(wsdlPort.getFeatures(), true);
 303             terminal = createSEIInvokerTube(seiModel,invoker,binding);
 304         }
 305 
 306         // Process @HandlerChain, if handler-chain is not set via Deployment Descriptor
 307         if (processHandlerAnnotation) {
 308             processHandlerAnnotation(binding, implType, serviceName, portName);
 309         }
 310         // Selects only required metadata for this endpoint from the passed-in metadata
 311         if (primaryDoc != null) {
 312             docList = findMetadataClosure(primaryDoc, docList, resolver);
 313         }
 314 
 315         ServiceDefinitionImpl serviceDefiniton = (primaryDoc != null) ? new ServiceDefinitionImpl(docList, primaryDoc) : null;
 316 
 317         return create(serviceName, portName, binding, container, seiModel, wsdlPort, implType, serviceDefiniton,
 318                         terminal, isTransportSynchronous, policyMap);
 319     }
 320 
 321     protected <T> WSEndpoint<T> create(QName serviceName, QName portName, WSBinding binding, Container container, SEIModel seiModel, WSDLPort wsdlPort, Class<T> implType, ServiceDefinitionImpl serviceDefinition, EndpointAwareTube terminal, boolean isTransportSynchronous, PolicyMap policyMap) {
 322         return new WSEndpointImpl<T>(serviceName, portName, binding, container, seiModel,
 323                         wsdlPort, implType, serviceDefinition, terminal, isTransportSynchronous, policyMap);
 324     }
 325 
 326     protected boolean isUseProviderTube(Class<?> implType, boolean isStandard) {
 327         return !isStandard || implType.getAnnotation(WebServiceProvider.class)!=null;
 328     }
 329 
 330     protected EndpointAwareTube createSEIInvokerTube(AbstractSEIModelImpl seiModel, Invoker invoker, WSBinding binding) {
 331         return new SEIInvokerTube(seiModel,invoker,binding);
 332     }
 333 
 334     protected <T> EndpointAwareTube createProviderInvokerTube(final Class<T> implType, final WSBinding binding,
 335                                                               final Invoker invoker, final Container container) {
 336         return ProviderInvokerTube.create(implType, binding, invoker, container);
 337     }
 338     /**
 339      * Goes through the original metadata documents and collects the required ones.
 340      * This done traversing from primary WSDL and its imports until it builds a
 341      * complete set of documents(transitive closure) for the endpoint.
 342      *
 343      * @param primaryDoc primary WSDL doc
 344      * @param docList complete metadata
 345      * @return new metadata that doesn't contain extraneous documents.
 346      */
 347     private static Collection<SDDocumentImpl> findMetadataClosure(
 348             final SDDocumentImpl primaryDoc, final Collection<SDDocumentImpl> docList, final EntityResolver resolver) {
 349         return new AbstractCollection<SDDocumentImpl>() {
 350             @Override
 351             public Iterator<SDDocumentImpl> iterator() {
 352                 // create a map for old metadata
 353                 Map<String, SDDocumentImpl> oldMap = new HashMap<String, SDDocumentImpl>();
 354                 Iterator<SDDocumentImpl> oldDocs = docList.iterator();
 355 
 356                 // create a map for new metadata
 357                 Map<String, SDDocumentImpl> newMap = new HashMap<String, SDDocumentImpl>();
 358                 newMap.put(primaryDoc.getSystemId().toString(), primaryDoc);
 359 
 360                 List<String> remaining = new ArrayList<String>();
 361                 remaining.addAll(primaryDoc.getImports());
 362                 while(!remaining.isEmpty()) {
 363                     String url = remaining.remove(0);
 364                     SDDocumentImpl doc = oldMap.get(url);
 365                     if (doc == null) {
 366                         while (oldDocs.hasNext()) {
 367                             SDDocumentImpl old = oldDocs.next();
 368                             String id = old.getSystemId().toString();
 369                             oldMap.put(id, old);
 370                             if (id.equals(url)) {
 371                                 doc = old;
 372                                 break;
 373                             }
 374                         }
 375 
 376                         if (doc == null) {
 377                             // old metadata doesn't have this imported doc, may be external
 378                                 if (resolver != null) {
 379                                         try {
 380                                                 InputSource source = resolver.resolveEntity(null, url);
 381                                                 if (source != null) {
 382                                                         MutableXMLStreamBuffer xsb = new MutableXMLStreamBuffer();
 383                                                         XMLStreamReader reader = XmlUtil.newXMLInputFactory(true).createXMLStreamReader(source.getByteStream());
 384                                                         xsb.createFromXMLStreamReader(reader);
 385 
 386                                                         SDDocumentSource sdocSource = SDDocumentImpl.create(new URL(url), xsb);
 387                                                         doc = SDDocumentImpl.create(sdocSource, null, null);
 388                                                 }
 389                                         } catch (Exception ex) {
 390                                                 ex.printStackTrace();
 391                                         }
 392                                 }
 393                         }
 394                     }
 395                     // Check if new metadata already contains this doc
 396                     if (doc != null && !newMap.containsKey(url)) {
 397                         newMap.put(url, doc);
 398                         remaining.addAll(doc.getImports());
 399                     }
 400                 }
 401 
 402                 return newMap.values().iterator();
 403             }
 404 
 405             @Override
 406             public int size() {
 407                 int size = 0;
 408                 Iterator<SDDocumentImpl> it = iterator();
 409                 while (it.hasNext()) {
 410                     it.next();
 411                     size++;
 412                 }
 413                 return size;
 414             }
 415 
 416             @Override
 417             public void clear() {
 418                 throw new UnsupportedOperationException();
 419             }
 420 
 421             @Override
 422             public boolean isEmpty() {
 423                 return docList.isEmpty();
 424             }
 425         };
 426     }
 427 
 428     private static <T> void processHandlerAnnotation(WSBinding binding, Class<T> implType, QName serviceName, QName portName) {
 429         HandlerAnnotationInfo chainInfo =
 430                 HandlerAnnotationProcessor.buildHandlerInfo(
 431                         implType, serviceName, portName, binding);
 432         if (chainInfo != null) {
 433             binding.setHandlerChain(chainInfo.getHandlers());
 434             if (binding instanceof SOAPBinding) {
 435                 ((SOAPBinding) binding).setRoles(chainInfo.getRoles());
 436             }
 437         }
 438 
 439     }
 440 
 441     /**
 442      * Verifies if the endpoint implementor class has @WebService or @WebServiceProvider
 443      * annotation
 444      *
 445      * @return
 446      *       true if it is a Provider or AsyncProvider endpoint
 447      *       false otherwise
 448      * @throws java.lang.IllegalArgumentException
 449      *      If it doesn't have any one of @WebService or @WebServiceProvider
 450      *      If it has both @WebService and @WebServiceProvider annotations
 451      */
 452     public static boolean verifyImplementorClass(Class<?> clz) {
 453         return verifyImplementorClass(clz, null);
 454     }
 455 
 456     /**
 457      * Verifies if the endpoint implementor class has @WebService or @WebServiceProvider
 458      * annotation; passing MetadataReader instance allows to read annotations from
 459      * xml descriptor instead of class's annotations
 460      *
 461      * @return
 462      *       true if it is a Provider or AsyncProvider endpoint
 463      *       false otherwise
 464      * @throws java.lang.IllegalArgumentException
 465      *      If it doesn't have any one of @WebService or @WebServiceProvider
 466      *      If it has both @WebService and @WebServiceProvider annotations
 467      */
 468     public static boolean verifyImplementorClass(Class<?> clz, MetadataReader metadataReader) {
 469 
 470         if (metadataReader == null) {
 471             metadataReader = new ReflectAnnotationReader();
 472         }
 473 
 474         WebServiceProvider wsProvider = metadataReader.getAnnotation(WebServiceProvider.class, clz);
 475         WebService ws = metadataReader.getAnnotation(WebService.class, clz);
 476         if (wsProvider == null && ws == null) {
 477             throw new IllegalArgumentException(clz +" has neither @WebService nor @WebServiceProvider annotation");
 478         }
 479         if (wsProvider != null && ws != null) {
 480             throw new IllegalArgumentException(clz +" has both @WebService and @WebServiceProvider annotations");
 481         }
 482         if (wsProvider != null) {
 483             if (Provider.class.isAssignableFrom(clz) || AsyncProvider.class.isAssignableFrom(clz)) {
 484                 return true;
 485             }
 486             throw new IllegalArgumentException(clz +" doesn't implement Provider or AsyncProvider interface");
 487         }
 488         return false;
 489     }
 490 
 491 
 492     private static AbstractSEIModelImpl createSEIModel(WSDLPort wsdlPort,
 493                                                        Class<?> implType, @NotNull QName serviceName, @NotNull QName portName, WSBinding binding,
 494                                                        SDDocumentSource primaryWsdl) {
 495                 DatabindingFactory fac = DatabindingFactory.newInstance();
 496                 DatabindingConfig config = new DatabindingConfig();
 497                 config.setEndpointClass(implType);
 498                 config.getMappingInfo().setServiceName(serviceName);
 499                 config.setWsdlPort(wsdlPort);
 500                 config.setWSBinding(binding);
 501                 config.setClassLoader(implType.getClassLoader());
 502                 config.getMappingInfo().setPortName(portName);
 503                 if (primaryWsdl != null) config.setWsdlURL(primaryWsdl.getSystemId());
 504         config.setMetadataReader(getExternalMetadatReader(implType, binding));
 505 
 506                 com.sun.xml.internal.ws.db.DatabindingImpl rt = (com.sun.xml.internal.ws.db.DatabindingImpl)fac.createRuntime(config);
 507                 return (AbstractSEIModelImpl) rt.getModel();
 508     }
 509 
 510     public static MetadataReader getExternalMetadatReader(Class<?> implType, WSBinding binding) {
 511         com.oracle.webservices.internal.api.databinding.ExternalMetadataFeature ef = binding.getFeature(
 512                 com.oracle.webservices.internal.api.databinding.ExternalMetadataFeature.class);
 513         // TODO-Miran: would it be necessary to disable secure xml processing?
 514         if (ef != null)
 515             return ef.getMetadataReader(implType.getClassLoader(), false);
 516         return null;
 517     }
 518 
 519     /**
 520      *Set the mtom enable setting from wsdl model (mtom policy assertion) on to @link WSBinding} if DD has
 521      * not already set it on BindingID. Also check conflicts.
 522      */
 523     /*
 524     private static void applyEffectiveMtomSetting(WSDLBoundPortType wsdlBinding, WSBinding binding){
 525         if(wsdlBinding.isMTOMEnabled()){
 526             BindingID bindingId = binding.getBindingId();
 527             if(bindingId.isMTOMEnabled() == null){
 528                 binding.setMTOMEnabled(true);
 529             }else if (bindingId.isMTOMEnabled() != null && bindingId.isMTOMEnabled() == Boolean.FALSE){
 530                 //TODO: i18N
 531                 throw new ServerRtException("Deployment failed! Mtom policy assertion in WSDL is enabled whereas the deplyment descriptor setting wants to disable it!");
 532             }
 533         }
 534     }
 535     */
 536     /**
 537      * If service name is not already set via DD or programmatically, it uses
 538      * annotations {@link WebServiceProvider}, {@link WebService} on implementorClass to get PortName.
 539      *
 540      * @return non-null service name
 541      */
 542     public static @NotNull QName getDefaultServiceName(Class<?> implType) {
 543         return getDefaultServiceName(implType, null);
 544     }
 545 
 546     public static @NotNull QName getDefaultServiceName(Class<?> implType, MetadataReader metadataReader) {
 547         return getDefaultServiceName(implType, true, metadataReader);
 548     }
 549 
 550     public static @NotNull QName getDefaultServiceName(Class<?> implType, boolean isStandard) {
 551         return getDefaultServiceName(implType, isStandard, null);
 552     }
 553 
 554     public static @NotNull QName getDefaultServiceName(Class<?> implType, boolean isStandard, MetadataReader metadataReader) {
 555         if (metadataReader == null) {
 556             metadataReader = new ReflectAnnotationReader();
 557         }
 558         QName serviceName;
 559         WebServiceProvider wsProvider = metadataReader.getAnnotation(WebServiceProvider.class, implType);
 560         if (wsProvider!=null) {
 561             String tns = wsProvider.targetNamespace();
 562             String local = wsProvider.serviceName();
 563             serviceName = new QName(tns, local);
 564         } else {
 565             serviceName = RuntimeModeler.getServiceName(implType, metadataReader, isStandard);
 566         }
 567         assert serviceName != null;
 568         return serviceName;
 569     }
 570 
 571     /**
 572      * If portName is not already set via DD or programmatically, it uses
 573      * annotations on implementorClass to get PortName.
 574      *
 575      * @return non-null port name
 576      */
 577     public static @NotNull QName getDefaultPortName(QName serviceName, Class<?> implType) {
 578         return getDefaultPortName(serviceName, implType, null);
 579     }
 580 
 581     public static @NotNull QName getDefaultPortName(QName serviceName, Class<?> implType, MetadataReader metadataReader) {
 582         return getDefaultPortName(serviceName, implType, true, metadataReader);
 583     }
 584 
 585     public static @NotNull QName getDefaultPortName(QName serviceName, Class<?> implType, boolean isStandard) {
 586         return getDefaultPortName(serviceName, implType, isStandard, null);
 587     }
 588 
 589     public static @NotNull QName getDefaultPortName(QName serviceName, Class<?> implType, boolean isStandard, MetadataReader metadataReader) {
 590         if (metadataReader == null) {
 591             metadataReader = new ReflectAnnotationReader();
 592         }
 593         QName portName;
 594         WebServiceProvider wsProvider = metadataReader.getAnnotation(WebServiceProvider.class, implType);
 595         if (wsProvider!=null) {
 596             String tns = wsProvider.targetNamespace();
 597             String local = wsProvider.portName();
 598             portName = new QName(tns, local);
 599         } else {
 600             portName = RuntimeModeler.getPortName(implType, metadataReader, serviceName.getNamespaceURI(), isStandard);
 601         }
 602         assert portName != null;
 603         return portName;
 604     }
 605 
 606     /**
 607      * Returns the wsdl from @WebService, or @WebServiceProvider annotation using
 608      * wsdlLocation element.
 609      *
 610      * @param implType
 611      *      endpoint implementation class
 612      *      make sure that you called {@link #verifyImplementorClass} on it.
 613      * @return wsdl if there is wsdlLocation, else null
 614      */
 615     public static @Nullable String getWsdlLocation(Class<?> implType) {
 616         return getWsdlLocation(implType, new ReflectAnnotationReader());
 617     }
 618 
 619     /**
 620      * Returns the wsdl from @WebService, or @WebServiceProvider annotation using
 621      * wsdlLocation element.
 622      *
 623      * @param implType
 624      *      endpoint implementation class
 625      *      make sure that you called {@link #verifyImplementorClass} on it.
 626      * @return wsdl if there is wsdlLocation, else null
 627      */
 628     public static @Nullable String getWsdlLocation(Class<?> implType, MetadataReader metadataReader) {
 629 
 630         if (metadataReader == null) {
 631             metadataReader = new ReflectAnnotationReader();
 632         }
 633 
 634         WebService ws = metadataReader.getAnnotation(WebService.class, implType);
 635         if (ws != null) {
 636             return nullIfEmpty(ws.wsdlLocation());
 637         } else {
 638             WebServiceProvider wsProvider = implType.getAnnotation(WebServiceProvider.class);
 639             assert wsProvider != null;
 640             return nullIfEmpty(wsProvider.wsdlLocation());
 641         }
 642     }
 643 
 644     private static String nullIfEmpty(String string) {
 645         if (string.length() < 1) {
 646             string = null;
 647         }
 648         return string;
 649     }
 650 
 651     /**
 652      * Generates the WSDL and XML Schema for the endpoint if necessary
 653      * It generates WSDL only for SOAP1.1, and for XSOAP1.2 bindings
 654      */
 655     private static SDDocumentImpl generateWSDL(WSBinding binding, AbstractSEIModelImpl seiModel, Collection<SDDocumentImpl> docs,
 656                                                Container container, Class implType) {
 657         BindingID bindingId = binding.getBindingId();
 658         if (!bindingId.canGenerateWSDL()) {
 659             throw new ServerRtException("can.not.generate.wsdl", bindingId);
 660         }
 661 
 662         if (bindingId.toString().equals(SOAPBindingImpl.X_SOAP12HTTP_BINDING)) {
 663             String msg = ServerMessages.GENERATE_NON_STANDARD_WSDL();
 664             logger.warning(msg);
 665         }
 666 
 667         // Generate WSDL and schema documents using runtime model
 668         WSDLGenResolver wsdlResolver = new WSDLGenResolver(docs,seiModel.getServiceQName(),seiModel.getPortTypeName());
 669         WSDLGenInfo wsdlGenInfo = new WSDLGenInfo();
 670         wsdlGenInfo.setWsdlResolver(wsdlResolver);
 671         wsdlGenInfo.setContainer(container);
 672         wsdlGenInfo.setExtensions(ServiceFinder.find(WSDLGeneratorExtension.class).toArray());
 673         wsdlGenInfo.setInlineSchemas(false);
 674         wsdlGenInfo.setSecureXmlProcessingDisabled(isSecureXmlProcessingDisabled(binding.getFeatures()));
 675         seiModel.getDatabinding().generateWSDL(wsdlGenInfo);
 676 //        WSDLGenerator wsdlGen = new WSDLGenerator(seiModel, wsdlResolver, binding, container, implType, false,
 677 //                ServiceFinder.find(WSDLGeneratorExtension.class).toArray());
 678 //        wsdlGen.doGeneration();
 679         return wsdlResolver.updateDocs();
 680     }
 681 
 682     private static boolean isSecureXmlProcessingDisabled(WSFeatureList featureList) {
 683         // TODO-Miran: would it be necessary to disable secure xml processing?
 684         return false;
 685     }
 686 
 687     /**
 688      * Builds {@link SDDocumentImpl} from {@link SDDocumentSource}.
 689      */
 690     private static Collection<SDDocumentImpl> categoriseMetadata(
 691         final Iterator<SDDocumentSource> src, final QName serviceName, final QName portTypeName) {
 692 
 693         return new AbstractCollection<SDDocumentImpl>() {
 694             private final Collection<SDDocumentImpl> theConverted = new ArrayList<SDDocumentImpl>();
 695 
 696             @Override
 697             public boolean add(SDDocumentImpl arg0) {
 698                 return theConverted.add(arg0);
 699             }
 700 
 701             @Override
 702             public Iterator<SDDocumentImpl> iterator() {
 703                 return new Iterator<SDDocumentImpl>() {
 704                     private Iterator<SDDocumentImpl> convIt = theConverted.iterator();
 705                     @Override
 706                     public boolean hasNext() {
 707                         if (convIt != null && convIt.hasNext())
 708                             return true;
 709                         return src.hasNext();
 710                     }
 711 
 712                     @Override
 713                     public SDDocumentImpl next() {
 714                         if (convIt != null && convIt.hasNext())
 715                             return convIt.next();
 716                         convIt = null;
 717                         if (!src.hasNext())
 718                             throw new NoSuchElementException();
 719                         SDDocumentImpl next = SDDocumentImpl.create(src.next(),serviceName,portTypeName);
 720                         theConverted.add(next);
 721                         return next;
 722                     }
 723 
 724                     @Override
 725                     public void remove() {
 726                         throw new UnsupportedOperationException();
 727                     }
 728                 };
 729             }
 730 
 731             @Override
 732             public int size() {
 733                 throw new UnsupportedOperationException();
 734             }
 735 
 736             @Override
 737             public boolean isEmpty() {
 738                 if (!theConverted.isEmpty())
 739                     return false;
 740                 return !src.hasNext();
 741             }
 742         };
 743     }
 744 
 745     /**
 746      * Verifies whether the given primaryWsdl contains the given serviceName.
 747      * If the WSDL doesn't have the service, it throws an WebServiceException.
 748      */
 749     private static void verifyPrimaryWSDL(@NotNull SDDocumentSource primaryWsdl, @NotNull QName serviceName) {
 750         SDDocumentImpl primaryDoc = SDDocumentImpl.create(primaryWsdl,serviceName,null);
 751         if (!(primaryDoc instanceof SDDocument.WSDL)) {
 752             throw new WebServiceException(primaryWsdl.getSystemId()+
 753                     " is not a WSDL. But it is passed as a primary WSDL");
 754         }
 755         SDDocument.WSDL wsdlDoc = (SDDocument.WSDL)primaryDoc;
 756         if (!wsdlDoc.hasService()) {
 757             if(wsdlDoc.getAllServices().isEmpty())
 758                 throw new WebServiceException("Not a primary WSDL="+primaryWsdl.getSystemId()+
 759                         " since it doesn't have Service "+serviceName);
 760             else
 761                 throw new WebServiceException("WSDL "+primaryDoc.getSystemId()
 762                         +" has the following services "+wsdlDoc.getAllServices()
 763                         +" but not "+serviceName+". Maybe you forgot to specify a serviceName and/or targetNamespace in @WebService/@WebServiceProvider?");
 764         }
 765     }
 766 
 767     /**
 768      * Finds the primary WSDL document from the list of metadata documents. If
 769      * there are two metadata documents that qualify for primary, it throws an
 770      * exception. If there are two metadata documents that qualify for porttype,
 771      * it throws an exception.
 772      *
 773      * @return primay wsdl document, null if is not there in the docList
 774      *
 775      */
 776     private static @Nullable SDDocumentImpl findPrimary(@NotNull Collection<SDDocumentImpl> docList) {
 777         SDDocumentImpl primaryDoc = null;
 778         boolean foundConcrete = false;
 779         boolean foundAbstract = false;
 780         for(SDDocumentImpl doc : docList) {
 781             if (doc instanceof SDDocument.WSDL) {
 782                 SDDocument.WSDL wsdlDoc = (SDDocument.WSDL)doc;
 783                 if (wsdlDoc.hasService()) {
 784                     primaryDoc = doc;
 785                     if (foundConcrete) {
 786                         throw new ServerRtException("duplicate.primary.wsdl", doc.getSystemId() );
 787                     }
 788                     foundConcrete = true;
 789                 }
 790                 if (wsdlDoc.hasPortType()) {
 791                     if (foundAbstract) {
 792                         throw new ServerRtException("duplicate.abstract.wsdl", doc.getSystemId());
 793                     }
 794                     foundAbstract = true;
 795                 }
 796             }
 797         }
 798         return primaryDoc;
 799     }
 800 
 801     /**
 802      * Parses the primary WSDL and returns the {@link WSDLPort} for the given service and port names
 803      *
 804      * @param primaryWsdl Primary WSDL
 805      * @param metadata it may contain imported WSDL and schema documents
 806      * @param serviceName service name in wsdl
 807      * @param portName port name in WSDL
 808      * @param container container in which this service is running
 809      * @return non-null wsdl port object
 810      */
 811     private static @NotNull WSDLPort getWSDLPort(SDDocumentSource primaryWsdl, Collection<? extends SDDocumentSource> metadata,
 812                                                      @NotNull QName serviceName, @NotNull QName portName, Container container,
 813                                                      EntityResolver resolver) {
 814         URL wsdlUrl = primaryWsdl.getSystemId();
 815         try {
 816             // TODO: delegate to another entity resolver
 817             WSDLModel wsdlDoc = RuntimeWSDLParser.parse(
 818                 new Parser(primaryWsdl), new EntityResolverImpl(metadata, resolver),
 819                     false, container, ServiceFinder.find(WSDLParserExtension.class).toArray());
 820             if(wsdlDoc.getServices().size() == 0) {
 821                 throw new ServerRtException(ServerMessages.localizableRUNTIME_PARSER_WSDL_NOSERVICE_IN_WSDLMODEL(wsdlUrl));
 822             }
 823             WSDLService wsdlService = wsdlDoc.getService(serviceName);
 824             if (wsdlService == null) {
 825                 throw new ServerRtException(ServerMessages.localizableRUNTIME_PARSER_WSDL_INCORRECTSERVICE(serviceName,wsdlUrl));
 826             }
 827             WSDLPort wsdlPort = wsdlService.get(portName);
 828             if (wsdlPort == null) {
 829                 throw new ServerRtException(ServerMessages.localizableRUNTIME_PARSER_WSDL_INCORRECTSERVICEPORT(serviceName, portName, wsdlUrl));
 830             }
 831             return wsdlPort;
 832         } catch (IOException e) {
 833             throw new ServerRtException("runtime.parser.wsdl", wsdlUrl,e);
 834         } catch (XMLStreamException e) {
 835             throw new ServerRtException("runtime.saxparser.exception", e.getMessage(), e.getLocation(), e);
 836         } catch (SAXException e) {
 837             throw new ServerRtException("runtime.parser.wsdl", wsdlUrl,e);
 838         } catch (ServiceConfigurationError e) {
 839             throw new ServerRtException("runtime.parser.wsdl", wsdlUrl,e);
 840         }
 841     }
 842 
 843     /**
 844      * {@link XMLEntityResolver} that can resolve to {@link SDDocumentSource}s.
 845      */
 846     private static final class EntityResolverImpl implements XMLEntityResolver {
 847         private Iterator<? extends SDDocumentSource> origMetadata;
 848         private Map<String,SDDocumentSource> metadata = new ConcurrentHashMap<String,SDDocumentSource>();
 849         private EntityResolver resolver;
 850 
 851         public EntityResolverImpl(Collection<? extends SDDocumentSource> metadata, EntityResolver resolver) {
 852             this.origMetadata = metadata.iterator();
 853             this.resolver = resolver;
 854         }
 855 
 856         public Parser resolveEntity (String publicId, String systemId) throws IOException, XMLStreamException {
 857             if (systemId != null) {
 858                 SDDocumentSource doc = metadata.get(systemId);
 859                 if (doc != null)
 860                     return new Parser(doc);
 861                 synchronized(this) {
 862                     while(origMetadata.hasNext()) {
 863                         doc = origMetadata.next();
 864                         String extForm = doc.getSystemId().toExternalForm();
 865                         this.metadata.put(extForm,doc);
 866                         if (systemId.equals(extForm))
 867                             return new Parser(doc);
 868                     }
 869                 }
 870             }
 871             if (resolver != null) {
 872                 try {
 873                     InputSource source = resolver.resolveEntity(publicId, systemId);
 874                     if (source != null) {
 875                         Parser p = new Parser(null, XMLStreamReaderFactory.create(source, true));
 876                         return p;
 877                     }
 878                 } catch (SAXException e) {
 879                     throw new XMLStreamException(e);
 880                 }
 881             }
 882             return null;
 883         }
 884 
 885     }
 886 
 887     private static final Logger logger = Logger.getLogger(
 888         com.sun.xml.internal.ws.util.Constants.LoggingDomain + ".server.endpoint");
 889 
 890     private static class CollectionCollection<T> extends AbstractCollection<T> {
 891 
 892         private final Collection<Collection<? extends T>> cols = new ArrayList<Collection<? extends T>>();
 893 
 894         @Override
 895         public Iterator<T> iterator() {
 896             final Iterator<Collection<? extends T>> colIt = cols.iterator();
 897             return new Iterator<T>() {
 898                 private Iterator<? extends T> current = null;
 899 
 900                 @Override
 901                 public boolean hasNext() {
 902                     if (current == null || !current.hasNext()) {
 903                         do {
 904                             if (!colIt.hasNext())
 905                                 return false;
 906                             current = colIt.next().iterator();
 907                         } while (!current.hasNext());
 908                         return true;
 909                     }
 910                     return true;
 911                 }
 912 
 913                 @Override
 914                 public T next() {
 915                     if (!hasNext())
 916                         throw new NoSuchElementException();
 917                     return current.next();
 918                 }
 919 
 920                 @Override
 921                 public void remove() {
 922                     if (current == null)
 923                         throw new IllegalStateException();
 924                     current.remove();
 925                 }
 926             };
 927         }
 928 
 929         @Override
 930         public int size() {
 931             int size = 0;
 932             for (Collection<? extends T> c : cols)
 933                 size += c.size();
 934             return size;
 935         }
 936 
 937         @Override
 938         public boolean add(T arg0) {
 939             return cols.add(Collections.singleton(arg0));
 940         }
 941 
 942         @Override
 943         public boolean addAll(Collection<? extends T> arg0) {
 944             return cols.add(arg0);
 945         }
 946 
 947         @Override
 948         public void clear() {
 949             cols.clear();
 950         }
 951 
 952         @Override
 953         public boolean isEmpty() {
 954             return !iterator().hasNext();
 955         }
 956     }
 957 }