1 /* 2 * Copyright (c) 1997, 2013, 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.ArrayList; 93 import java.util.Collection; 94 import java.util.HashMap; 95 import java.util.List; 96 import java.util.Map; 97 import java.util.logging.Logger; 98 99 /** 100 * Entry point to the JAX-WS RI server-side runtime. 101 * 102 * @author Kohsuke Kawaguchi 103 * @author Jitendra Kotamraju 104 */ 105 public class EndpointFactory { 106 private static final EndpointFactory instance = new EndpointFactory(); 107 108 public static EndpointFactory getInstance() { 109 return instance; 110 } 111 112 /** 113 * Implements {@link WSEndpoint#create}. 114 * 115 * No need to take WebServiceContext implementation. When InvokerPipe is 116 * instantiated, it calls InstanceResolver to set up a WebServiceContext. 117 * We shall only take delegate to getUserPrincipal and isUserInRole from adapter. 118 * 119 * <p> 120 * Nobody else should be calling this method. 121 */ 122 public static <T> WSEndpoint<T> createEndpoint( 123 Class<T> implType, boolean processHandlerAnnotation, @Nullable Invoker invoker, 124 @Nullable QName serviceName, @Nullable QName portName, 125 @Nullable Container container, @Nullable WSBinding binding, 126 @Nullable SDDocumentSource primaryWsdl, 127 @Nullable Collection<? extends SDDocumentSource> metadata, 128 EntityResolver resolver, boolean isTransportSynchronous) { 129 return createEndpoint(implType, processHandlerAnnotation, invoker, serviceName, 130 portName, container, binding, primaryWsdl, metadata, resolver, isTransportSynchronous, true); 131 } 132 133 public static <T> WSEndpoint<T> createEndpoint( 134 Class<T> implType, boolean processHandlerAnnotation, @Nullable Invoker invoker, 135 @Nullable QName serviceName, @Nullable QName portName, 136 @Nullable Container container, @Nullable WSBinding binding, 137 @Nullable SDDocumentSource primaryWsdl, 138 @Nullable Collection<? extends SDDocumentSource> metadata, 139 EntityResolver resolver, boolean isTransportSynchronous, boolean isStandard) { 140 EndpointFactory factory = container != null ? container.getSPI(EndpointFactory.class) : null; 141 if (factory == null) 142 factory = EndpointFactory.getInstance(); 143 144 return factory.create( 145 implType,processHandlerAnnotation, invoker,serviceName,portName,container,binding,primaryWsdl,metadata,resolver,isTransportSynchronous,isStandard); 146 } 147 148 /** 149 * Implements {@link WSEndpoint#create}. 150 * 151 * No need to take WebServiceContext implementation. When InvokerPipe is 152 * instantiated, it calls InstanceResolver to set up a WebServiceContext. 153 * We shall only take delegate to getUserPrincipal and isUserInRole from adapter. 154 * 155 * <p> 156 * Nobody else should be calling this method. 157 */ 158 public <T> WSEndpoint<T> create( 159 Class<T> implType, boolean processHandlerAnnotation, @Nullable Invoker invoker, 160 @Nullable QName serviceName, @Nullable QName portName, 161 @Nullable Container container, @Nullable WSBinding binding, 162 @Nullable SDDocumentSource primaryWsdl, 163 @Nullable Collection<? extends SDDocumentSource> metadata, 164 EntityResolver resolver, boolean isTransportSynchronous) { 165 return create(implType, processHandlerAnnotation, invoker, serviceName, 166 portName, container, binding, primaryWsdl, metadata, resolver, isTransportSynchronous, 167 true); 168 169 } 170 171 public <T> WSEndpoint<T> create( 172 Class<T> implType, boolean processHandlerAnnotation, @Nullable Invoker invoker, 173 @Nullable QName serviceName, @Nullable QName portName, 174 @Nullable Container container, @Nullable WSBinding binding, 175 @Nullable SDDocumentSource primaryWsdl, 176 @Nullable Collection<? extends SDDocumentSource> metadata, 177 EntityResolver resolver, boolean isTransportSynchronous, boolean isStandard) { 178 179 if(implType ==null) 180 throw new IllegalArgumentException(); 181 182 MetadataReader metadataReader = getExternalMetadatReader(implType, binding); 183 184 if (isStandard) { 185 verifyImplementorClass(implType, metadataReader); 186 } 187 188 if (invoker == null) { 189 invoker = InstanceResolver.createDefault(implType).createInvoker(); 190 } 191 192 List<SDDocumentSource> md = new ArrayList<SDDocumentSource>(); 193 if(metadata!=null) 194 md.addAll(metadata); 195 196 if(primaryWsdl!=null && !md.contains(primaryWsdl)) 197 md.add(primaryWsdl); 198 199 if(container==null) 200 container = ContainerResolver.getInstance().getContainer(); 201 202 if(serviceName==null) 203 serviceName = getDefaultServiceName(implType, metadataReader); 204 205 if(portName==null) 206 portName = getDefaultPortName(serviceName,implType, metadataReader); 207 208 {// error check 209 String serviceNS = serviceName.getNamespaceURI(); 210 String portNS = portName.getNamespaceURI(); 211 if (!serviceNS.equals(portNS)) { 212 throw new ServerRtException("wrong.tns.for.port",portNS, serviceNS); 213 } 214 } 215 216 // setting a default binding 217 if (binding == null) 218 binding = BindingImpl.create(BindingID.parse(implType)); 219 220 if ( isStandard && primaryWsdl != null) { 221 verifyPrimaryWSDL(primaryWsdl, serviceName); 222 } 223 224 QName portTypeName = null; 225 if (isStandard && implType.getAnnotation(WebServiceProvider.class)==null) { 226 portTypeName = RuntimeModeler.getPortTypeName(implType, metadataReader); 227 } 228 229 // Categorises the documents as WSDL, Schema etc 230 List<SDDocumentImpl> docList = categoriseMetadata(md, serviceName, portTypeName); 231 // Finds the primary WSDL and makes sure that metadata doesn't have 232 // two concrete or abstract WSDLs 233 SDDocumentImpl primaryDoc = primaryWsdl != null ? SDDocumentImpl.create(primaryWsdl,serviceName,portTypeName) : findPrimary(docList); 234 235 EndpointAwareTube terminal; 236 WSDLPort wsdlPort = null; 237 AbstractSEIModelImpl seiModel = null; 238 // create WSDL model 239 if (primaryDoc != null) { 240 wsdlPort = getWSDLPort(primaryDoc, docList, serviceName, portName, container, resolver); 241 } 242 243 WebServiceFeatureList features=((BindingImpl)binding).getFeatures(); 244 if (isStandard) { 245 features.parseAnnotations(implType); 246 } 247 PolicyMap policyMap = null; 248 // create terminal pipe that invokes the application 249 if (isUseProviderTube(implType, isStandard)) { 250 //TODO incase of Provider, provide a way to User for complete control of the message processing by giving 251 // ability to turn off the WSDL/Policy based features and its associated tubes. 252 253 //Even in case of Provider, merge all features configured via WSDL/Policy or deployment configuration 254 Iterable<WebServiceFeature> configFtrs; 255 if(wsdlPort != null) { 256 policyMap = wsdlPort.getOwner().getParent().getPolicyMap(); 257 //Merge features from WSDL and other policy configuration 258 configFtrs = wsdlPort.getFeatures(); 259 } else { 260 //No WSDL, so try to merge features from Policy configuration 261 policyMap = PolicyResolverFactory.create().resolve( 262 new PolicyResolver.ServerContext(null, container, implType, false)); 263 configFtrs = PolicyUtil.getPortScopedFeatures(policyMap,serviceName,portName); 264 } 265 features.mergeFeatures(configFtrs, true); 266 terminal = createProviderInvokerTube(implType, binding, invoker, container); 267 } else { 268 // Create runtime model for non Provider endpoints 269 seiModel = createSEIModel(wsdlPort, implType, serviceName, portName, binding, primaryDoc); 270 if(binding instanceof SOAPBindingImpl){ 271 //set portKnownHeaders on Binding, so that they can be used for MU processing 272 ((SOAPBindingImpl)binding).setPortKnownHeaders( 273 ((SOAPSEIModel)seiModel).getKnownHeaders()); 274 } 275 // Generate WSDL for SEI endpoints(not for Provider endpoints) 276 if (primaryDoc == null) { 277 primaryDoc = generateWSDL(binding, seiModel, docList, container, implType); 278 // create WSDL model 279 wsdlPort = getWSDLPort(primaryDoc, docList, serviceName, portName, container, resolver); 280 seiModel.freeze(wsdlPort); 281 } 282 policyMap = wsdlPort.getOwner().getParent().getPolicyMap(); 283 // New Features might have been added in WSDL through Policy. 284 //Merge features from WSDL and other policy configuration 285 // This sets only the wsdl features that are not already set(enabled/disabled) 286 features.mergeFeatures(wsdlPort.getFeatures(), true); 287 terminal = createSEIInvokerTube(seiModel,invoker,binding); 288 } 289 290 // Process @HandlerChain, if handler-chain is not set via Deployment Descriptor 291 if (processHandlerAnnotation) { 292 processHandlerAnnotation(binding, implType, serviceName, portName); 293 } 294 // Selects only required metadata for this endpoint from the passed-in metadata 295 if (primaryDoc != null) { 296 docList = findMetadataClosure(primaryDoc, docList, resolver); 297 } 298 299 ServiceDefinitionImpl serviceDefiniton = (primaryDoc != null) ? new ServiceDefinitionImpl(docList, primaryDoc) : null; 300 301 return create(serviceName, portName, binding, container, seiModel, wsdlPort, implType, serviceDefiniton, 302 terminal, isTransportSynchronous, policyMap); 303 } 304 305 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) { 306 return new WSEndpointImpl<T>(serviceName, portName, binding, container, seiModel, 307 wsdlPort, implType, serviceDefinition, terminal, isTransportSynchronous, policyMap); 308 } 309 310 protected boolean isUseProviderTube(Class<?> implType, boolean isStandard) { 311 return !isStandard || implType.getAnnotation(WebServiceProvider.class)!=null; 312 } 313 314 protected EndpointAwareTube createSEIInvokerTube(AbstractSEIModelImpl seiModel, Invoker invoker, WSBinding binding) { 315 return new SEIInvokerTube(seiModel,invoker,binding); 316 } 317 318 protected <T> EndpointAwareTube createProviderInvokerTube(final Class<T> implType, final WSBinding binding, 319 final Invoker invoker, final Container container) { 320 return ProviderInvokerTube.create(implType, binding, invoker, container); 321 } 322 /** 323 * Goes through the original metadata documents and collects the required ones. 324 * This done traversing from primary WSDL and its imports until it builds a 325 * complete set of documents(transitive closure) for the endpoint. 326 * 327 * @param primaryDoc primary WSDL doc 328 * @param docList complete metadata 329 * @return new metadata that doesn't contain extraneous documnets. 330 */ 331 private static List<SDDocumentImpl> findMetadataClosure(SDDocumentImpl primaryDoc, List<SDDocumentImpl> docList, EntityResolver resolver) { 332 // create a map for old metadata 333 Map<String, SDDocumentImpl> oldMap = new HashMap<String, SDDocumentImpl>(); 334 for(SDDocumentImpl doc : docList) { 335 oldMap.put(doc.getSystemId().toString(), doc); 336 } 337 // create a map for new metadata 338 Map<String, SDDocumentImpl> newMap = new HashMap<String, SDDocumentImpl>(); 339 newMap.put(primaryDoc.getSystemId().toString(), primaryDoc); 340 341 List<String> remaining = new ArrayList<String>(); 342 remaining.addAll(primaryDoc.getImports()); 343 while(!remaining.isEmpty()) { 344 String url = remaining.remove(0); 345 SDDocumentImpl doc = oldMap.get(url); 346 if (doc == null) { 347 // old metadata doesn't have this imported doc, may be external 348 if (resolver != null) { 349 try { 350 InputSource source = resolver.resolveEntity(null, url); 351 if (source != null) { 352 MutableXMLStreamBuffer xsb = new MutableXMLStreamBuffer(); 353 XMLStreamReader reader = XmlUtil.newXMLInputFactory(true).createXMLStreamReader(source.getByteStream()); 354 xsb.createFromXMLStreamReader(reader); 355 356 SDDocumentSource sdocSource = SDDocumentImpl.create(new URL(url), xsb); 357 doc = SDDocumentImpl.create(sdocSource, null, null); 358 } 359 } catch (Exception ex) { 360 ex.printStackTrace(); 361 } 362 } 363 } 364 // Check if new metadata already contains this doc 365 if (doc != null && !newMap.containsKey(url)) { 366 newMap.put(url, doc); 367 remaining.addAll(doc.getImports()); 368 } 369 } 370 List<SDDocumentImpl> newMetadata = new ArrayList<SDDocumentImpl>(); 371 newMetadata.addAll(newMap.values()); 372 return newMetadata; 373 } 374 375 private static <T> void processHandlerAnnotation(WSBinding binding, Class<T> implType, QName serviceName, QName portName) { 376 HandlerAnnotationInfo chainInfo = 377 HandlerAnnotationProcessor.buildHandlerInfo( 378 implType, serviceName, portName, binding); 379 if (chainInfo != null) { 380 binding.setHandlerChain(chainInfo.getHandlers()); 381 if (binding instanceof SOAPBinding) { 382 ((SOAPBinding) binding).setRoles(chainInfo.getRoles()); 383 } 384 } 385 386 } 387 388 /** 389 * Verifies if the endpoint implementor class has @WebService or @WebServiceProvider 390 * annotation 391 * 392 * @return 393 * true if it is a Provider or AsyncProvider endpoint 394 * false otherwise 395 * @throws java.lang.IllegalArgumentException 396 * If it doesn't have any one of @WebService or @WebServiceProvider 397 * If it has both @WebService and @WebServiceProvider annotations 398 */ 399 public static boolean verifyImplementorClass(Class<?> clz) { 400 return verifyImplementorClass(clz, null); 401 } 402 403 /** 404 * Verifies if the endpoint implementor class has @WebService or @WebServiceProvider 405 * annotation; passing MetadataReader instance allows to read annotations from 406 * xml descriptor instead of class's annotations 407 * 408 * @return 409 * true if it is a Provider or AsyncProvider endpoint 410 * false otherwise 411 * @throws java.lang.IllegalArgumentException 412 * If it doesn't have any one of @WebService or @WebServiceProvider 413 * If it has both @WebService and @WebServiceProvider annotations 414 */ 415 public static boolean verifyImplementorClass(Class<?> clz, MetadataReader metadataReader) { 416 417 if (metadataReader == null) { 418 metadataReader = new ReflectAnnotationReader(); 419 } 420 421 WebServiceProvider wsProvider = metadataReader.getAnnotation(WebServiceProvider.class, clz); 422 WebService ws = metadataReader.getAnnotation(WebService.class, clz); 423 if (wsProvider == null && ws == null) { 424 throw new IllegalArgumentException(clz +" has neither @WebService nor @WebServiceProvider annotation"); 425 } 426 if (wsProvider != null && ws != null) { 427 throw new IllegalArgumentException(clz +" has both @WebService and @WebServiceProvider annotations"); 428 } 429 if (wsProvider != null) { 430 if (Provider.class.isAssignableFrom(clz) || AsyncProvider.class.isAssignableFrom(clz)) { 431 return true; 432 } 433 throw new IllegalArgumentException(clz +" doesn't implement Provider or AsyncProvider interface"); 434 } 435 return false; 436 } 437 438 439 private static AbstractSEIModelImpl createSEIModel(WSDLPort wsdlPort, 440 Class<?> implType, @NotNull QName serviceName, @NotNull QName portName, WSBinding binding, 441 SDDocumentSource primaryWsdl) { 442 DatabindingFactory fac = DatabindingFactory.newInstance(); 443 DatabindingConfig config = new DatabindingConfig(); 444 config.setEndpointClass(implType); 445 config.getMappingInfo().setServiceName(serviceName); 446 config.setWsdlPort(wsdlPort); 447 config.setWSBinding(binding); 448 config.setClassLoader(implType.getClassLoader()); 449 config.getMappingInfo().setPortName(portName); 450 if (primaryWsdl != null) config.setWsdlURL(primaryWsdl.getSystemId()); 451 config.setMetadataReader(getExternalMetadatReader(implType, binding)); 452 453 com.sun.xml.internal.ws.db.DatabindingImpl rt = (com.sun.xml.internal.ws.db.DatabindingImpl)fac.createRuntime(config); 454 return (AbstractSEIModelImpl) rt.getModel(); 455 } 456 457 public static MetadataReader getExternalMetadatReader(Class<?> implType, WSBinding binding) { 458 com.oracle.webservices.internal.api.databinding.ExternalMetadataFeature ef = binding.getFeature( 459 com.oracle.webservices.internal.api.databinding.ExternalMetadataFeature.class); 460 // TODO-Miran: would it be necessary to disable secure xml processing? 461 if (ef != null) 462 return ef.getMetadataReader(implType.getClassLoader(), false); 463 return null; 464 } 465 466 /** 467 *Set the mtom enable setting from wsdl model (mtom policy assertion) on to @link WSBinding} if DD has 468 * not already set it on BindingID. Also check conflicts. 469 */ 470 /* 471 private static void applyEffectiveMtomSetting(WSDLBoundPortType wsdlBinding, WSBinding binding){ 472 if(wsdlBinding.isMTOMEnabled()){ 473 BindingID bindingId = binding.getBindingId(); 474 if(bindingId.isMTOMEnabled() == null){ 475 binding.setMTOMEnabled(true); 476 }else if (bindingId.isMTOMEnabled() != null && bindingId.isMTOMEnabled() == Boolean.FALSE){ 477 //TODO: i18N 478 throw new ServerRtException("Deployment failed! Mtom policy assertion in WSDL is enabled whereas the deplyment descriptor setting wants to disable it!"); 479 } 480 } 481 } 482 */ 483 /** 484 * If service name is not already set via DD or programmatically, it uses 485 * annotations {@link WebServiceProvider}, {@link WebService} on implementorClass to get PortName. 486 * 487 * @return non-null service name 488 */ 489 public static @NotNull QName getDefaultServiceName(Class<?> implType) { 490 return getDefaultServiceName(implType, null); 491 } 492 493 public static @NotNull QName getDefaultServiceName(Class<?> implType, MetadataReader metadataReader) { 494 return getDefaultServiceName(implType, true, metadataReader); 495 } 496 497 public static @NotNull QName getDefaultServiceName(Class<?> implType, boolean isStandard) { 498 return getDefaultServiceName(implType, isStandard, null); 499 } 500 501 public static @NotNull QName getDefaultServiceName(Class<?> implType, boolean isStandard, MetadataReader metadataReader) { 502 if (metadataReader == null) { 503 metadataReader = new ReflectAnnotationReader(); 504 } 505 QName serviceName; 506 WebServiceProvider wsProvider = metadataReader.getAnnotation(WebServiceProvider.class, implType); 507 if (wsProvider!=null) { 508 String tns = wsProvider.targetNamespace(); 509 String local = wsProvider.serviceName(); 510 serviceName = new QName(tns, local); 511 } else { 512 serviceName = RuntimeModeler.getServiceName(implType, metadataReader, isStandard); 513 } 514 assert serviceName != null; 515 return serviceName; 516 } 517 518 /** 519 * If portName is not already set via DD or programmatically, it uses 520 * annotations on implementorClass to get PortName. 521 * 522 * @return non-null port name 523 */ 524 public static @NotNull QName getDefaultPortName(QName serviceName, Class<?> implType) { 525 return getDefaultPortName(serviceName, implType, null); 526 } 527 528 public static @NotNull QName getDefaultPortName(QName serviceName, Class<?> implType, MetadataReader metadataReader) { 529 return getDefaultPortName(serviceName, implType, true, metadataReader); 530 } 531 532 public static @NotNull QName getDefaultPortName(QName serviceName, Class<?> implType, boolean isStandard) { 533 return getDefaultPortName(serviceName, implType, isStandard, null); 534 } 535 536 public static @NotNull QName getDefaultPortName(QName serviceName, Class<?> implType, boolean isStandard, MetadataReader metadataReader) { 537 if (metadataReader == null) { 538 metadataReader = new ReflectAnnotationReader(); 539 } 540 QName portName; 541 WebServiceProvider wsProvider = metadataReader.getAnnotation(WebServiceProvider.class, implType); 542 if (wsProvider!=null) { 543 String tns = wsProvider.targetNamespace(); 544 String local = wsProvider.portName(); 545 portName = new QName(tns, local); 546 } else { 547 portName = RuntimeModeler.getPortName(implType, metadataReader, serviceName.getNamespaceURI(), isStandard); 548 } 549 assert portName != null; 550 return portName; 551 } 552 553 /** 554 * Returns the wsdl from @WebService, or @WebServiceProvider annotation using 555 * wsdlLocation element. 556 * 557 * @param implType 558 * endpoint implementation class 559 * make sure that you called {@link #verifyImplementorClass} on it. 560 * @return wsdl if there is wsdlLocation, else null 561 */ 562 public static @Nullable String getWsdlLocation(Class<?> implType) { 563 return getWsdlLocation(implType, new ReflectAnnotationReader()); 564 } 565 566 /** 567 * Returns the wsdl from @WebService, or @WebServiceProvider annotation using 568 * wsdlLocation element. 569 * 570 * @param implType 571 * endpoint implementation class 572 * make sure that you called {@link #verifyImplementorClass} on it. 573 * @return wsdl if there is wsdlLocation, else null 574 */ 575 public static @Nullable String getWsdlLocation(Class<?> implType, MetadataReader metadataReader) { 576 577 if (metadataReader == null) { 578 metadataReader = new ReflectAnnotationReader(); 579 } 580 581 WebService ws = metadataReader.getAnnotation(WebService.class, implType); 582 if (ws != null) { 583 return nullIfEmpty(ws.wsdlLocation()); 584 } else { 585 WebServiceProvider wsProvider = implType.getAnnotation(WebServiceProvider.class); 586 assert wsProvider != null; 587 return nullIfEmpty(wsProvider.wsdlLocation()); 588 } 589 } 590 591 private static String nullIfEmpty(String string) { 592 if (string.length() < 1) { 593 string = null; 594 } 595 return string; 596 } 597 598 /** 599 * Generates the WSDL and XML Schema for the endpoint if necessary 600 * It generates WSDL only for SOAP1.1, and for XSOAP1.2 bindings 601 */ 602 private static SDDocumentImpl generateWSDL(WSBinding binding, AbstractSEIModelImpl seiModel, List<SDDocumentImpl> docs, 603 Container container, Class implType) { 604 BindingID bindingId = binding.getBindingId(); 605 if (!bindingId.canGenerateWSDL()) { 606 throw new ServerRtException("can.not.generate.wsdl", bindingId); 607 } 608 609 if (bindingId.toString().equals(SOAPBindingImpl.X_SOAP12HTTP_BINDING)) { 610 String msg = ServerMessages.GENERATE_NON_STANDARD_WSDL(); 611 logger.warning(msg); 612 } 613 614 // Generate WSDL and schema documents using runtime model 615 WSDLGenResolver wsdlResolver = new WSDLGenResolver(docs,seiModel.getServiceQName(),seiModel.getPortTypeName()); 616 WSDLGenInfo wsdlGenInfo = new WSDLGenInfo(); 617 wsdlGenInfo.setWsdlResolver(wsdlResolver); 618 wsdlGenInfo.setContainer(container); 619 wsdlGenInfo.setExtensions(ServiceFinder.find(WSDLGeneratorExtension.class).toArray()); 620 wsdlGenInfo.setInlineSchemas(false); 621 wsdlGenInfo.setSecureXmlProcessingDisabled(isSecureXmlProcessingDisabled(binding.getFeatures())); 622 seiModel.getDatabinding().generateWSDL(wsdlGenInfo); 623 // WSDLGenerator wsdlGen = new WSDLGenerator(seiModel, wsdlResolver, binding, container, implType, false, 624 // ServiceFinder.find(WSDLGeneratorExtension.class).toArray()); 625 // wsdlGen.doGeneration(); 626 return wsdlResolver.updateDocs(); 627 } 628 629 private static boolean isSecureXmlProcessingDisabled(WSFeatureList featureList) { 630 // TODO-Miran: would it be necessary to disable secure xml processing? 631 return false; 632 } 633 634 /** 635 * Builds {@link SDDocumentImpl} from {@link SDDocumentSource}. 636 */ 637 private static List<SDDocumentImpl> categoriseMetadata( 638 List<SDDocumentSource> src, QName serviceName, QName portTypeName) { 639 640 List<SDDocumentImpl> r = new ArrayList<SDDocumentImpl>(src.size()); 641 for (SDDocumentSource doc : src) { 642 r.add(SDDocumentImpl.create(doc,serviceName,portTypeName)); 643 } 644 return r; 645 } 646 647 /** 648 * Verifies whether the given primaryWsdl contains the given serviceName. 649 * If the WSDL doesn't have the service, it throws an WebServiceException. 650 */ 651 private static void verifyPrimaryWSDL(@NotNull SDDocumentSource primaryWsdl, @NotNull QName serviceName) { 652 SDDocumentImpl primaryDoc = SDDocumentImpl.create(primaryWsdl,serviceName,null); 653 if (!(primaryDoc instanceof SDDocument.WSDL)) { 654 throw new WebServiceException(primaryWsdl.getSystemId()+ 655 " is not a WSDL. But it is passed as a primary WSDL"); 656 } 657 SDDocument.WSDL wsdlDoc = (SDDocument.WSDL)primaryDoc; 658 if (!wsdlDoc.hasService()) { 659 if(wsdlDoc.getAllServices().isEmpty()) 660 throw new WebServiceException("Not a primary WSDL="+primaryWsdl.getSystemId()+ 661 " since it doesn't have Service "+serviceName); 662 else 663 throw new WebServiceException("WSDL "+primaryDoc.getSystemId() 664 +" has the following services "+wsdlDoc.getAllServices() 665 +" but not "+serviceName+". Maybe you forgot to specify a serviceName and/or targetNamespace in @WebService/@WebServiceProvider?"); 666 } 667 } 668 669 /** 670 * Finds the primary WSDL document from the list of metadata documents. If 671 * there are two metadata documents that qualify for primary, it throws an 672 * exception. If there are two metadata documents that qualify for porttype, 673 * it throws an exception. 674 * 675 * @return primay wsdl document, null if is not there in the docList 676 * 677 */ 678 private static @Nullable SDDocumentImpl findPrimary(@NotNull List<SDDocumentImpl> docList) { 679 SDDocumentImpl primaryDoc = null; 680 boolean foundConcrete = false; 681 boolean foundAbstract = false; 682 for(SDDocumentImpl doc : docList) { 683 if (doc instanceof SDDocument.WSDL) { 684 SDDocument.WSDL wsdlDoc = (SDDocument.WSDL)doc; 685 if (wsdlDoc.hasService()) { 686 primaryDoc = doc; 687 if (foundConcrete) { 688 throw new ServerRtException("duplicate.primary.wsdl", doc.getSystemId() ); 689 } 690 foundConcrete = true; 691 } 692 if (wsdlDoc.hasPortType()) { 693 if (foundAbstract) { 694 throw new ServerRtException("duplicate.abstract.wsdl", doc.getSystemId()); 695 } 696 foundAbstract = true; 697 } 698 } 699 } 700 return primaryDoc; 701 } 702 703 /** 704 * Parses the primary WSDL and returns the {@link WSDLPort} for the given service and port names 705 * 706 * @param primaryWsdl Primary WSDL 707 * @param metadata it may contain imported WSDL and schema documents 708 * @param serviceName service name in wsdl 709 * @param portName port name in WSDL 710 * @param container container in which this service is running 711 * @return non-null wsdl port object 712 */ 713 private static @NotNull WSDLPort getWSDLPort(SDDocumentSource primaryWsdl, List<? extends SDDocumentSource> metadata, 714 @NotNull QName serviceName, @NotNull QName portName, Container container, 715 EntityResolver resolver) { 716 URL wsdlUrl = primaryWsdl.getSystemId(); 717 try { 718 // TODO: delegate to another entity resolver 719 WSDLModel wsdlDoc = RuntimeWSDLParser.parse( 720 new Parser(primaryWsdl), new EntityResolverImpl(metadata, resolver), 721 false, container, ServiceFinder.find(WSDLParserExtension.class).toArray()); 722 if(wsdlDoc.getServices().size() == 0) { 723 throw new ServerRtException(ServerMessages.localizableRUNTIME_PARSER_WSDL_NOSERVICE_IN_WSDLMODEL(wsdlUrl)); 724 } 725 WSDLService wsdlService = wsdlDoc.getService(serviceName); 726 if (wsdlService == null) { 727 throw new ServerRtException(ServerMessages.localizableRUNTIME_PARSER_WSDL_INCORRECTSERVICE(serviceName,wsdlUrl)); 728 } 729 WSDLPort wsdlPort = wsdlService.get(portName); 730 if (wsdlPort == null) { 731 throw new ServerRtException(ServerMessages.localizableRUNTIME_PARSER_WSDL_INCORRECTSERVICEPORT(serviceName, portName, wsdlUrl)); 732 } 733 return wsdlPort; 734 } catch (IOException e) { 735 throw new ServerRtException("runtime.parser.wsdl", wsdlUrl,e); 736 } catch (XMLStreamException e) { 737 throw new ServerRtException("runtime.saxparser.exception", e.getMessage(), e.getLocation(), e); 738 } catch (SAXException e) { 739 throw new ServerRtException("runtime.parser.wsdl", wsdlUrl,e); 740 } catch (ServiceConfigurationError e) { 741 throw new ServerRtException("runtime.parser.wsdl", wsdlUrl,e); 742 } 743 } 744 745 /** 746 * {@link XMLEntityResolver} that can resolve to {@link SDDocumentSource}s. 747 */ 748 private static final class EntityResolverImpl implements XMLEntityResolver { 749 private Map<String,SDDocumentSource> metadata = new HashMap<String,SDDocumentSource>(); 750 private EntityResolver resolver; 751 752 public EntityResolverImpl(List<? extends SDDocumentSource> metadata, EntityResolver resolver) { 753 for (SDDocumentSource doc : metadata) { 754 this.metadata.put(doc.getSystemId().toExternalForm(),doc); 755 } 756 this.resolver = resolver; 757 } 758 759 public Parser resolveEntity (String publicId, String systemId) throws IOException, XMLStreamException { 760 if (systemId != null) { 761 SDDocumentSource doc = metadata.get(systemId); 762 if (doc != null) 763 return new Parser(doc); 764 } 765 if (resolver != null) { 766 try { 767 InputSource source = resolver.resolveEntity(publicId, systemId); 768 if (source != null) { 769 Parser p = new Parser(null, XMLStreamReaderFactory.create(source, true)); 770 return p; 771 } 772 } catch (SAXException e) { 773 throw new XMLStreamException(e); 774 } 775 } 776 return null; 777 } 778 779 } 780 781 private static final Logger logger = Logger.getLogger( 782 com.sun.xml.internal.ws.util.Constants.LoggingDomain + ".server.endpoint"); 783 }