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 }