|
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.tools.internal.ws.util; |
|
27 |
|
28 import com.sun.istack.internal.NotNull; |
|
29 import com.sun.tools.internal.ws.resources.WscompileMessages; |
|
30 import com.sun.tools.internal.ws.wscompile.WsimportListener; |
|
31 import com.sun.tools.internal.ws.wscompile.WsimportOptions; |
|
32 import com.sun.tools.internal.ws.wsdl.parser.DOMForest; |
|
33 import com.sun.tools.internal.ws.wsdl.parser.MetadataFinder; |
|
34 import com.sun.xml.internal.txw2.output.IndentingXMLStreamWriter; |
|
35 import com.sun.xml.internal.ws.api.server.PortAddressResolver; |
|
36 import com.sun.xml.internal.ws.streaming.SourceReaderFactory; |
|
37 import com.sun.xml.internal.ws.wsdl.parser.WSDLConstants; |
|
38 import com.sun.xml.internal.ws.wsdl.writer.DocumentLocationResolver; |
|
39 import com.sun.xml.internal.ws.wsdl.writer.WSDLPatcher; |
|
40 import org.w3c.dom.Document; |
|
41 import org.w3c.dom.Element; |
|
42 import org.w3c.dom.Node; |
|
43 import org.w3c.dom.NodeList; |
|
44 |
|
45 import javax.xml.namespace.QName; |
|
46 import javax.xml.stream.XMLOutputFactory; |
|
47 import javax.xml.stream.XMLStreamException; |
|
48 import javax.xml.stream.XMLStreamReader; |
|
49 import javax.xml.stream.XMLStreamWriter; |
|
50 import javax.xml.transform.dom.DOMSource; |
|
51 import java.io.*; |
|
52 import java.net.MalformedURLException; |
|
53 import java.net.URL; |
|
54 import java.util.HashMap; |
|
55 import java.util.Map; |
|
56 import java.util.Set; |
|
57 |
|
58 /** |
|
59 * @author Rama Pulavarthi |
|
60 */ |
|
61 public 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 } |