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 26package com.sun.tools.internal.ws.util; 27 28import com.sun.istack.internal.NotNull; 29import com.sun.tools.internal.ws.resources.WscompileMessages; 30import com.sun.tools.internal.ws.wscompile.WsimportListener; 31import com.sun.tools.internal.ws.wscompile.WsimportOptions; 32import com.sun.tools.internal.ws.wsdl.parser.DOMForest; 33import com.sun.tools.internal.ws.wsdl.parser.MetadataFinder; 34import com.sun.xml.internal.txw2.output.IndentingXMLStreamWriter; 35import com.sun.xml.internal.ws.api.server.PortAddressResolver; 36import com.sun.xml.internal.ws.streaming.SourceReaderFactory; 37import com.sun.xml.internal.ws.wsdl.parser.WSDLConstants; 38import com.sun.xml.internal.ws.wsdl.writer.DocumentLocationResolver; 39import com.sun.xml.internal.ws.wsdl.writer.WSDLPatcher; 40import org.w3c.dom.Document; 41import org.w3c.dom.Element; 42import org.w3c.dom.Node; 43import org.w3c.dom.NodeList; 44 45import javax.xml.namespace.QName; 46import javax.xml.stream.XMLOutputFactory; 47import javax.xml.stream.XMLStreamException; 48import javax.xml.stream.XMLStreamReader; 49import javax.xml.stream.XMLStreamWriter; 50import javax.xml.transform.dom.DOMSource; 51import java.io.*; 52import java.net.MalformedURLException; 53import java.net.URL; 54import java.util.HashMap; 55import java.util.Map; 56import java.util.Set; 57 58/** 59 * @author Rama Pulavarthi 60 */ 61public class WSDLFetcher { 62 private WsimportOptions options; 63 private WsimportListener listener; 64 public WSDLFetcher(WsimportOptions options, WsimportListener listener) { 65 this.options = options; 66 this.listener = listener; 67 } 68 69 70 /** 71 * Fetches the wsdls in the DOMForest to the options.destDir 72 * @param forest 73 * @return location of fetched root WSDL document 74 * @throws IOException 75 * @throws XMLStreamException 76 * @throws FileNotFoundException 77 */ 78 public String fetchWsdls(MetadataFinder forest) throws IOException, XMLStreamException { 79 String rootWsdl = null; 80 for(String root: forest.getRootDocuments()) { 81 rootWsdl = root; 82 } 83 84 Set<String> externalRefs = forest.getExternalReferences(); 85 Map<String,String> documentMap = createDocumentMap(forest, getWSDLDownloadDir(), rootWsdl, externalRefs); 86 String rootWsdlName = fetchFile(rootWsdl,forest, documentMap,getWSDLDownloadDir()); 87 for(String reference: forest.getExternalReferences()) { 88 fetchFile(reference,forest,documentMap,getWSDLDownloadDir()); 89 } 90 return WSDL_PATH +"/" + rootWsdlName; 91 } 92 93 private String fetchFile(final String doc, DOMForest forest, final Map<String, String> documentMap, File destDir) throws IOException, XMLStreamException { 94 95 DocumentLocationResolver docLocator = createDocResolver(doc, forest, documentMap); 96 WSDLPatcher wsdlPatcher = new WSDLPatcher(new PortAddressResolver() { 97 @Override 98 public String getAddressFor(@NotNull QName serviceName, @NotNull String portName) { 99 return null; 100 } 101 }, docLocator); 102 103 XMLStreamReader xsr = null; 104 XMLStreamWriter xsw = null; 105 OutputStream os = null; 106 String resolvedRootWsdl = null; 107 try { 108 XMLOutputFactory writerfactory; 109 xsr = SourceReaderFactory.createSourceReader(new DOMSource(forest.get(doc)), false); 110 writerfactory = XMLOutputFactory.newInstance(); 111 resolvedRootWsdl = docLocator.getLocationFor(null, doc); 112 File outFile = new File(destDir, resolvedRootWsdl); 113 os = new FileOutputStream(outFile); 114 if(options.verbose) { 115 listener.message(WscompileMessages.WSIMPORT_DOCUMENT_DOWNLOAD(doc,outFile)); 116 } 117 xsw = writerfactory.createXMLStreamWriter(os); 118 //DOMForest eats away the whitespace loosing all the indentation, so write it through 119 // indenting writer for better readability of fetched documents 120 IndentingXMLStreamWriter indentingWriter = new IndentingXMLStreamWriter(xsw); 121 wsdlPatcher.bridge(xsr, indentingWriter); 122 options.addGeneratedFile(outFile); 123 } finally { 124 try { 125 if (xsr != null) {xsr.close();} 126 if (xsw != null) {xsw.close();} 127 } finally { 128 if (os != null) {os.close();} 129 } 130 } 131 return resolvedRootWsdl; 132 133 134 } 135 private Map<String,String> createDocumentMap(MetadataFinder forest, File baseDir, final String rootWsdl, Set<String> externalReferences) { 136 Map<String,String> map = new HashMap<String,String>(); 137 String rootWsdlFileName = rootWsdl; 138 String rootWsdlName; 139 140 int slashIndex = rootWsdl.lastIndexOf("/"); 141 if( slashIndex >= 0) { 142 rootWsdlFileName = rootWsdl.substring(slashIndex+1); 143 } 144 if(!rootWsdlFileName.endsWith(WSDL_FILE_EXTENSION)) { 145 Document rootWsdlDoc = forest.get(rootWsdl); 146 NodeList serviceNodes = rootWsdlDoc.getElementsByTagNameNS(WSDLConstants.QNAME_SERVICE.getNamespaceURI(),WSDLConstants.QNAME_SERVICE.getLocalPart()); 147 if (serviceNodes.getLength() == 0) { 148 rootWsdlName = "Service"; 149 } else { 150 Node serviceNode = serviceNodes.item(0); 151 String serviceName = ((Element)serviceNode).getAttribute( WSDLConstants.ATTR_NAME); 152 rootWsdlName = serviceName; 153 } 154 rootWsdlFileName = rootWsdlName+ WSDL_FILE_EXTENSION; 155 } else { 156 rootWsdlName = rootWsdlFileName.substring(0,rootWsdlFileName.length()-5); 157 } 158 159 map.put(rootWsdl,sanitize(rootWsdlFileName)); 160 161 int i =1; 162 for(String ref: externalReferences) { 163 Document refDoc = forest.get(ref); 164 Element rootEl = refDoc.getDocumentElement(); 165 String fileExtn; 166 String fileName = null; 167 int index = ref.lastIndexOf("/"); 168 if (index >= 0) { 169 fileName = ref.substring(index + 1); 170 } 171 if(rootEl.getLocalName().equals(WSDLConstants.QNAME_DEFINITIONS.getLocalPart()) && rootEl.getNamespaceURI().equals(WSDLConstants.NS_WSDL)) { 172 fileExtn = WSDL_FILE_EXTENSION; 173 } else if(rootEl.getLocalName().equals(WSDLConstants.QNAME_SCHEMA.getLocalPart()) && rootEl.getNamespaceURI().equals(WSDLConstants.NS_XMLNS)) { 174 fileExtn = SCHEMA_FILE_EXTENSION; 175 } else { 176 fileExtn = ".xml"; 177 } 178 if(fileName != null && (fileName.endsWith(WSDL_FILE_EXTENSION) || fileName.endsWith(SCHEMA_FILE_EXTENSION))) { 179 map.put(ref, rootWsdlName+"_"+fileName); 180 } else { 181 map.put(ref, rootWsdlName+"_metadata"+ (i++) + fileExtn); 182 } 183 } 184 return map; 185 } 186 187 private DocumentLocationResolver createDocResolver(final String baseWsdl, final DOMForest forest, final Map<String,String> documentMap) { 188 return new DocumentLocationResolver() { 189 @Override 190 public String getLocationFor(String namespaceURI, String systemId) { 191 try { 192 URL reference = new URL(new URL(baseWsdl),systemId); 193 systemId = reference.toExternalForm(); 194 } catch (MalformedURLException e) { 195 throw new RuntimeException(e); 196 } 197 if(documentMap.get(systemId) != null) { 198 return documentMap.get(systemId); 199 } else { 200 String parsedEntity = forest.getReferencedEntityMap().get(systemId); 201 return documentMap.get(parsedEntity); 202 } 203 } 204 }; 205 } 206 207 private String sanitize(String fileName) { 208 fileName = fileName.replace('?', '.'); 209 StringBuilder sb = new StringBuilder(fileName); 210 for (int i = 0; i < sb.length(); i++) { 211 char c = sb.charAt(i); 212 if (Character.isLetterOrDigit(c) || 213 (c == '/') || 214 (c == '.') || 215 (c == '_') || 216 (c == ' ') || 217 (c == '-')) { 218 continue; 219 } else { 220 sb.setCharAt(i, '_'); 221 } 222 } 223 return sb.toString(); 224 } 225 226 private File getWSDLDownloadDir() { 227 File wsdlDir = new File(options.destDir, WSDL_PATH); 228 boolean created = wsdlDir.mkdirs(); 229 if (options.verbose && !created) { 230 listener.message(WscompileMessages.WSCOMPILE_NO_SUCH_DIRECTORY(wsdlDir)); 231 } 232 return wsdlDir; 233 } 234 235 private static String WSDL_PATH="META-INF/wsdl"; 236 private static String WSDL_FILE_EXTENSION=".wsdl"; 237 private static String SCHEMA_FILE_EXTENSION=".xsd"; 238} 239