1 /* 2 * Copyright (c) 1997, 2012, 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.Nullable; 29 import com.sun.xml.internal.ws.api.server.*; 30 import com.sun.xml.internal.ws.api.streaming.XMLStreamWriterFactory; 31 import com.sun.xml.internal.ws.streaming.XMLStreamReaderUtil; 32 import com.sun.xml.internal.ws.wsdl.SDDocumentResolver; 33 import com.sun.xml.internal.ws.util.RuntimeVersion; 34 import com.sun.xml.internal.ws.util.xml.XMLStreamReaderToXMLStreamWriter; 35 import com.sun.xml.internal.ws.wsdl.parser.ParserUtil; 36 import com.sun.xml.internal.ws.wsdl.parser.WSDLConstants; 37 import com.sun.xml.internal.ws.wsdl.writer.DocumentLocationResolver; 38 import com.sun.xml.internal.ws.wsdl.writer.WSDLPatcher; 39 40 import javax.xml.namespace.QName; 41 import javax.xml.stream.*; 42 import javax.xml.ws.WebServiceException; 43 import java.io.IOException; 44 import java.io.OutputStream; 45 import java.net.MalformedURLException; 46 import java.net.URL; 47 import java.util.HashSet; 48 import java.util.List; 49 import java.util.Set; 50 51 /** 52 * {@link SDDocument} implmentation. 53 * 54 * <p> 55 * This extends from {@link SDDocumentSource} so that 56 * JAX-WS server runtime code can use {@link SDDocument} 57 * as {@link SDDocumentSource}. 58 * 59 * @author Kohsuke Kawaguchi 60 * @author Jitendra Kotamraju 61 */ 62 public class SDDocumentImpl extends SDDocumentSource implements SDDocument { 63 64 private static final String NS_XSD = "http://www.w3.org/2001/XMLSchema"; 65 private static final QName SCHEMA_INCLUDE_QNAME = new QName(NS_XSD, "include"); 66 private static final QName SCHEMA_IMPORT_QNAME = new QName(NS_XSD, "import"); 67 private static final QName SCHEMA_REDEFINE_QNAME = new QName(NS_XSD, "redefine"); 68 private static final String VERSION_COMMENT = 69 " Published by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is "+RuntimeVersion.VERSION+". "; 70 71 private final QName rootName; 72 private final SDDocumentSource source; 73 74 /** 75 * Set when {@link ServiceDefinitionImpl} is constructed. 76 */ 77 @Nullable List<SDDocumentFilter> filters; 78 @Nullable SDDocumentResolver sddocResolver; 79 80 81 /** 82 * The original system ID of this document. 83 * 84 * When this document contains relative references to other resources, 85 * this field is used to find which {@link com.sun.xml.internal.ws.server.SDDocumentImpl} it refers to. 86 * 87 * Must not be null. 88 */ 89 private final URL url; 90 private final Set<String> imports; 91 92 /** 93 * Creates {@link SDDocument} from {@link SDDocumentSource}. 94 * @param src WSDL document infoset 95 * @param serviceName wsdl:service name 96 * @param portTypeName 97 * The information about the port of {@link WSEndpoint} to which this document is built for. 98 * These values are used to determine which document is the concrete and abstract WSDLs 99 * for this endpoint. 100 * 101 * @return null 102 * Always non-null. 103 */ 104 public static SDDocumentImpl create(SDDocumentSource src, QName serviceName, QName portTypeName) { 105 URL systemId = src.getSystemId(); 106 107 try { 108 // RuntimeWSDLParser parser = new RuntimeWSDLParser(null); 109 XMLStreamReader reader = src.read(); 110 try { 111 XMLStreamReaderUtil.nextElementContent(reader); 112 113 QName rootName = reader.getName(); 114 if(rootName.equals(WSDLConstants.QNAME_SCHEMA)) { 115 String tns = ParserUtil.getMandatoryNonEmptyAttribute(reader, WSDLConstants.ATTR_TNS); 116 Set<String> importedDocs = new HashSet<String>(); 117 while (XMLStreamReaderUtil.nextContent(reader) != XMLStreamConstants.END_DOCUMENT) { 118 if (reader.getEventType() != XMLStreamConstants.START_ELEMENT) 119 continue; 120 QName name = reader.getName(); 121 if (SCHEMA_INCLUDE_QNAME.equals(name) || SCHEMA_IMPORT_QNAME.equals(name) || 122 SCHEMA_REDEFINE_QNAME.equals(name)) { 123 String importedDoc = reader.getAttributeValue(null, "schemaLocation"); 124 if (importedDoc != null) { 125 importedDocs.add(new URL(src.getSystemId(), importedDoc).toString()); 126 } 127 } 128 } 129 return new SchemaImpl(rootName,systemId,src,tns,importedDocs); 130 } else if (rootName.equals(WSDLConstants.QNAME_DEFINITIONS)) { 131 String tns = ParserUtil.getMandatoryNonEmptyAttribute(reader, WSDLConstants.ATTR_TNS); 132 133 boolean hasPortType = false; 134 boolean hasService = false; 135 Set<String> importedDocs = new HashSet<String>(); 136 Set<QName> allServices = new HashSet<QName>(); 137 138 // if WSDL, parse more 139 while (XMLStreamReaderUtil.nextContent(reader) != XMLStreamConstants.END_DOCUMENT) { 140 if(reader.getEventType() != XMLStreamConstants.START_ELEMENT) 141 continue; 142 143 QName name = reader.getName(); 144 if (WSDLConstants.QNAME_PORT_TYPE.equals(name)) { 145 String pn = ParserUtil.getMandatoryNonEmptyAttribute(reader, WSDLConstants.ATTR_NAME); 146 if (portTypeName != null) { 147 if(portTypeName.getLocalPart().equals(pn)&&portTypeName.getNamespaceURI().equals(tns)) { 148 hasPortType = true; 149 } 150 } 151 } else if (WSDLConstants.QNAME_SERVICE.equals(name)) { 152 String sn = ParserUtil.getMandatoryNonEmptyAttribute(reader, WSDLConstants.ATTR_NAME); 153 QName sqn = new QName(tns,sn); 154 allServices.add(sqn); 155 if(serviceName.equals(sqn)) { 156 hasService = true; 157 } 158 } else if (WSDLConstants.QNAME_IMPORT.equals(name)) { 159 String importedDoc = reader.getAttributeValue(null, "location"); 160 if (importedDoc != null) { 161 importedDocs.add(new URL(src.getSystemId(), importedDoc).toString()); 162 } 163 } else if (SCHEMA_INCLUDE_QNAME.equals(name) || SCHEMA_IMPORT_QNAME.equals(name) || 164 SCHEMA_REDEFINE_QNAME.equals(name)) { 165 String importedDoc = reader.getAttributeValue(null, "schemaLocation"); 166 if (importedDoc != null) { 167 importedDocs.add(new URL(src.getSystemId(), importedDoc).toString()); 168 } 169 } 170 } 171 return new WSDLImpl( 172 rootName,systemId,src,tns,hasPortType,hasService,importedDocs,allServices); 173 } else { 174 return new SDDocumentImpl(rootName,systemId,src); 175 } 176 } finally { 177 reader.close(); 178 } 179 } catch (WebServiceException e) { 180 throw new ServerRtException("runtime.parser.wsdl", systemId,e); 181 } catch (IOException e) { 182 throw new ServerRtException("runtime.parser.wsdl", systemId,e); 183 } catch (XMLStreamException e) { 184 throw new ServerRtException("runtime.parser.wsdl", systemId,e); 185 } 186 } 187 188 protected SDDocumentImpl(QName rootName, URL url, SDDocumentSource source) { 189 this(rootName, url, source, new HashSet<String>()); 190 } 191 192 protected SDDocumentImpl(QName rootName, URL url, SDDocumentSource source, Set<String> imports) { 193 if (url == null) { 194 throw new IllegalArgumentException("Cannot construct SDDocument with null URL."); 195 } 196 this.rootName = rootName; 197 this.source = source; 198 this.url = url; 199 this.imports = imports; 200 } 201 202 void setFilters(List<SDDocumentFilter> filters) { 203 this.filters = filters; 204 } 205 206 void setResolver(SDDocumentResolver sddocResolver) { 207 this.sddocResolver = sddocResolver; 208 } 209 210 public QName getRootName() { 211 return rootName; 212 } 213 214 public boolean isWSDL() { 215 return false; 216 } 217 218 public boolean isSchema() { 219 return false; 220 } 221 222 public URL getURL() { 223 return url; 224 } 225 226 public XMLStreamReader read(XMLInputFactory xif) throws IOException, XMLStreamException { 227 return source.read(xif); 228 } 229 230 public XMLStreamReader read() throws IOException, XMLStreamException { 231 return source.read(); 232 } 233 234 public URL getSystemId() { 235 return url; 236 } 237 238 public Set<String> getImports() { 239 return imports; 240 } 241 242 public void writeTo(OutputStream os) throws IOException { 243 XMLStreamWriter w = null; 244 try { 245 //generate the WSDL with utf-8 encoding and XML version 1.0 246 w = XMLStreamWriterFactory.create(os, "UTF-8"); 247 w.writeStartDocument("UTF-8", "1.0"); 248 new XMLStreamReaderToXMLStreamWriter().bridge(source.read(), w); 249 w.writeEndDocument(); 250 } catch (XMLStreamException e) { 251 IOException ioe = new IOException(e.getMessage()); 252 ioe.initCause(e); 253 throw ioe; 254 } finally { 255 try { 256 if (w != null) 257 w.close(); 258 } catch (XMLStreamException e) { 259 IOException ioe = new IOException(e.getMessage()); 260 ioe.initCause(e); 261 throw ioe; 262 } 263 } 264 } 265 266 267 public void writeTo(PortAddressResolver portAddressResolver, DocumentAddressResolver resolver, OutputStream os) throws IOException { 268 XMLStreamWriter w = null; 269 try { 270 //generate the WSDL with utf-8 encoding and XML version 1.0 271 w = XMLStreamWriterFactory.create(os, "UTF-8"); 272 w.writeStartDocument("UTF-8", "1.0"); 273 writeTo(portAddressResolver,resolver,w); 274 w.writeEndDocument(); 275 } catch (XMLStreamException e) { 276 IOException ioe = new IOException(e.getMessage()); 277 ioe.initCause(e); 278 throw ioe; 279 } finally { 280 try { 281 if (w != null) 282 w.close(); 283 } catch (XMLStreamException e) { 284 IOException ioe = new IOException(e.getMessage()); 285 ioe.initCause(e); 286 throw ioe; 287 } 288 } 289 } 290 291 public void writeTo(PortAddressResolver portAddressResolver, DocumentAddressResolver resolver, XMLStreamWriter out) throws XMLStreamException, IOException { 292 if (filters != null) { 293 for (SDDocumentFilter f : filters) { 294 out = f.filter(this,out); 295 } 296 } 297 298 XMLStreamReader xsr = source.read(); 299 try { 300 out.writeComment(VERSION_COMMENT); 301 new WSDLPatcher(portAddressResolver, new DocumentLocationResolverImpl(resolver)).bridge(xsr,out); 302 } finally { 303 xsr.close(); 304 } 305 } 306 307 308 /** 309 * {@link SDDocument.Schema} implementation. 310 * 311 * @author Kohsuke Kawaguchi 312 */ 313 private static final class SchemaImpl extends SDDocumentImpl implements SDDocument.Schema { 314 private final String targetNamespace; 315 316 public SchemaImpl(QName rootName, URL url, SDDocumentSource source, String targetNamespace, 317 Set<String> imports) { 318 super(rootName, url, source, imports); 319 this.targetNamespace = targetNamespace; 320 } 321 322 public String getTargetNamespace() { 323 return targetNamespace; 324 } 325 326 public boolean isSchema() { 327 return true; 328 } 329 } 330 331 332 private static final class WSDLImpl extends SDDocumentImpl implements SDDocument.WSDL { 333 private final String targetNamespace; 334 private final boolean hasPortType; 335 private final boolean hasService; 336 private final Set<QName> allServices; 337 338 public WSDLImpl(QName rootName, URL url, SDDocumentSource source, String targetNamespace, boolean hasPortType, 339 boolean hasService, Set<String> imports,Set<QName> allServices) { 340 super(rootName, url, source, imports); 341 this.targetNamespace = targetNamespace; 342 this.hasPortType = hasPortType; 343 this.hasService = hasService; 344 this.allServices = allServices; 345 } 346 347 public String getTargetNamespace() { 348 return targetNamespace; 349 } 350 351 public boolean hasPortType() { 352 return hasPortType; 353 } 354 355 public boolean hasService() { 356 return hasService; 357 } 358 359 public Set<QName> getAllServices() { 360 return allServices; 361 } 362 363 public boolean isWSDL() { 364 return true; 365 } 366 } 367 368 private class DocumentLocationResolverImpl implements DocumentLocationResolver { 369 private DocumentAddressResolver delegate; 370 371 DocumentLocationResolverImpl(DocumentAddressResolver delegate) { 372 this.delegate = delegate; 373 } 374 375 public String getLocationFor(String namespaceURI, String systemId) { 376 if (sddocResolver == null) { 377 return systemId; 378 } 379 try { 380 URL ref = new URL(getURL(), systemId); 381 SDDocument refDoc = sddocResolver.resolve(ref.toExternalForm()); 382 if (refDoc == null) 383 return systemId; // not something we know. just leave it as is. 384 385 return delegate.getRelativeAddressFor(SDDocumentImpl.this, refDoc); 386 } catch (MalformedURLException mue) { 387 return null; 388 } 389 } 390 } 391 392 }