aoqi@0: /* aoqi@0: * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. Oracle designates this aoqi@0: * particular file as subject to the "Classpath" exception as provided aoqi@0: * by Oracle in the LICENSE file that accompanied this code. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: */ aoqi@0: aoqi@0: package com.sun.tools.internal.ws.util; aoqi@0: aoqi@0: import com.sun.istack.internal.NotNull; aoqi@0: import com.sun.tools.internal.ws.resources.WscompileMessages; aoqi@0: import com.sun.tools.internal.ws.wscompile.WsimportListener; aoqi@0: import com.sun.tools.internal.ws.wscompile.WsimportOptions; aoqi@0: import com.sun.tools.internal.ws.wsdl.parser.DOMForest; aoqi@0: import com.sun.tools.internal.ws.wsdl.parser.MetadataFinder; aoqi@0: import com.sun.xml.internal.txw2.output.IndentingXMLStreamWriter; aoqi@0: import com.sun.xml.internal.ws.api.server.PortAddressResolver; aoqi@0: import com.sun.xml.internal.ws.streaming.SourceReaderFactory; aoqi@0: import com.sun.xml.internal.ws.wsdl.parser.WSDLConstants; aoqi@0: import com.sun.xml.internal.ws.wsdl.writer.DocumentLocationResolver; aoqi@0: import com.sun.xml.internal.ws.wsdl.writer.WSDLPatcher; aoqi@0: import org.w3c.dom.Document; aoqi@0: import org.w3c.dom.Element; aoqi@0: import org.w3c.dom.Node; aoqi@0: import org.w3c.dom.NodeList; aoqi@0: aoqi@0: import javax.xml.namespace.QName; aoqi@0: import javax.xml.stream.XMLOutputFactory; aoqi@0: import javax.xml.stream.XMLStreamException; aoqi@0: import javax.xml.stream.XMLStreamReader; aoqi@0: import javax.xml.stream.XMLStreamWriter; aoqi@0: import javax.xml.transform.dom.DOMSource; aoqi@0: import java.io.*; aoqi@0: import java.net.MalformedURLException; aoqi@0: import java.net.URL; aoqi@0: import java.util.HashMap; aoqi@0: import java.util.Map; aoqi@0: import java.util.Set; aoqi@0: aoqi@0: /** aoqi@0: * @author Rama Pulavarthi aoqi@0: */ aoqi@0: public class WSDLFetcher { aoqi@0: private WsimportOptions options; aoqi@0: private WsimportListener listener; aoqi@0: public WSDLFetcher(WsimportOptions options, WsimportListener listener) { aoqi@0: this.options = options; aoqi@0: this.listener = listener; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: /** aoqi@0: * Fetches the wsdls in the DOMForest to the options.destDir aoqi@0: * @param forest aoqi@0: * @return location of fetched root WSDL document aoqi@0: * @throws IOException aoqi@0: * @throws XMLStreamException aoqi@0: * @throws FileNotFoundException aoqi@0: */ aoqi@0: public String fetchWsdls(MetadataFinder forest) throws IOException, XMLStreamException { aoqi@0: String rootWsdl = null; aoqi@0: for(String root: forest.getRootDocuments()) { aoqi@0: rootWsdl = root; aoqi@0: } aoqi@0: aoqi@0: Set externalRefs = forest.getExternalReferences(); aoqi@0: Map documentMap = createDocumentMap(forest, getWSDLDownloadDir(), rootWsdl, externalRefs); aoqi@0: String rootWsdlName = fetchFile(rootWsdl,forest, documentMap,getWSDLDownloadDir()); aoqi@0: for(String reference: forest.getExternalReferences()) { aoqi@0: fetchFile(reference,forest,documentMap,getWSDLDownloadDir()); aoqi@0: } aoqi@0: return WSDL_PATH +"/" + rootWsdlName; aoqi@0: } aoqi@0: aoqi@0: private String fetchFile(final String doc, DOMForest forest, final Map documentMap, File destDir) throws IOException, XMLStreamException { aoqi@0: aoqi@0: DocumentLocationResolver docLocator = createDocResolver(doc, forest, documentMap); aoqi@0: WSDLPatcher wsdlPatcher = new WSDLPatcher(new PortAddressResolver() { aoqi@0: @Override aoqi@0: public String getAddressFor(@NotNull QName serviceName, @NotNull String portName) { aoqi@0: return null; aoqi@0: } aoqi@0: }, docLocator); aoqi@0: aoqi@0: XMLStreamReader xsr = null; aoqi@0: XMLStreamWriter xsw = null; aoqi@0: OutputStream os = null; aoqi@0: String resolvedRootWsdl = null; aoqi@0: try { aoqi@0: XMLOutputFactory writerfactory; aoqi@0: xsr = SourceReaderFactory.createSourceReader(new DOMSource(forest.get(doc)), false); aoqi@0: writerfactory = XMLOutputFactory.newInstance(); aoqi@0: resolvedRootWsdl = docLocator.getLocationFor(null, doc); aoqi@0: File outFile = new File(destDir, resolvedRootWsdl); aoqi@0: os = new FileOutputStream(outFile); aoqi@0: if(options.verbose) { aoqi@0: listener.message(WscompileMessages.WSIMPORT_DOCUMENT_DOWNLOAD(doc,outFile)); aoqi@0: } aoqi@0: xsw = writerfactory.createXMLStreamWriter(os); aoqi@0: //DOMForest eats away the whitespace loosing all the indentation, so write it through aoqi@0: // indenting writer for better readability of fetched documents aoqi@0: IndentingXMLStreamWriter indentingWriter = new IndentingXMLStreamWriter(xsw); aoqi@0: wsdlPatcher.bridge(xsr, indentingWriter); aoqi@0: options.addGeneratedFile(outFile); aoqi@0: } finally { aoqi@0: try { aoqi@0: if (xsr != null) {xsr.close();} aoqi@0: if (xsw != null) {xsw.close();} aoqi@0: } finally { aoqi@0: if (os != null) {os.close();} aoqi@0: } aoqi@0: } aoqi@0: return resolvedRootWsdl; aoqi@0: aoqi@0: aoqi@0: } aoqi@0: private Map createDocumentMap(MetadataFinder forest, File baseDir, final String rootWsdl, Set externalReferences) { aoqi@0: Map map = new HashMap(); aoqi@0: String rootWsdlFileName = rootWsdl; aoqi@0: String rootWsdlName; aoqi@0: aoqi@0: int slashIndex = rootWsdl.lastIndexOf("/"); aoqi@0: if( slashIndex >= 0) { aoqi@0: rootWsdlFileName = rootWsdl.substring(slashIndex+1); aoqi@0: } aoqi@0: if(!rootWsdlFileName.endsWith(WSDL_FILE_EXTENSION)) { aoqi@0: Document rootWsdlDoc = forest.get(rootWsdl); aoqi@0: NodeList serviceNodes = rootWsdlDoc.getElementsByTagNameNS(WSDLConstants.QNAME_SERVICE.getNamespaceURI(),WSDLConstants.QNAME_SERVICE.getLocalPart()); aoqi@0: if (serviceNodes.getLength() == 0) { aoqi@0: rootWsdlName = "Service"; aoqi@0: } else { aoqi@0: Node serviceNode = serviceNodes.item(0); aoqi@0: String serviceName = ((Element)serviceNode).getAttribute( WSDLConstants.ATTR_NAME); aoqi@0: rootWsdlName = serviceName; aoqi@0: } aoqi@0: rootWsdlFileName = rootWsdlName+ WSDL_FILE_EXTENSION; aoqi@0: } else { aoqi@0: rootWsdlName = rootWsdlFileName.substring(0,rootWsdlFileName.length()-5); aoqi@0: } aoqi@0: aoqi@0: map.put(rootWsdl,sanitize(rootWsdlFileName)); aoqi@0: aoqi@0: int i =1; aoqi@0: for(String ref: externalReferences) { aoqi@0: Document refDoc = forest.get(ref); aoqi@0: Element rootEl = refDoc.getDocumentElement(); aoqi@0: String fileExtn; aoqi@0: String fileName = null; aoqi@0: int index = ref.lastIndexOf("/"); aoqi@0: if (index >= 0) { aoqi@0: fileName = ref.substring(index + 1); aoqi@0: } aoqi@0: if(rootEl.getLocalName().equals(WSDLConstants.QNAME_DEFINITIONS.getLocalPart()) && rootEl.getNamespaceURI().equals(WSDLConstants.NS_WSDL)) { aoqi@0: fileExtn = WSDL_FILE_EXTENSION; aoqi@0: } else if(rootEl.getLocalName().equals(WSDLConstants.QNAME_SCHEMA.getLocalPart()) && rootEl.getNamespaceURI().equals(WSDLConstants.NS_XMLNS)) { aoqi@0: fileExtn = SCHEMA_FILE_EXTENSION; aoqi@0: } else { aoqi@0: fileExtn = ".xml"; aoqi@0: } aoqi@0: if(fileName != null && (fileName.endsWith(WSDL_FILE_EXTENSION) || fileName.endsWith(SCHEMA_FILE_EXTENSION))) { aoqi@0: map.put(ref, rootWsdlName+"_"+fileName); aoqi@0: } else { aoqi@0: map.put(ref, rootWsdlName+"_metadata"+ (i++) + fileExtn); aoqi@0: } aoqi@0: } aoqi@0: return map; aoqi@0: } aoqi@0: aoqi@0: private DocumentLocationResolver createDocResolver(final String baseWsdl, final DOMForest forest, final Map documentMap) { aoqi@0: return new DocumentLocationResolver() { aoqi@0: @Override aoqi@0: public String getLocationFor(String namespaceURI, String systemId) { aoqi@0: try { aoqi@0: URL reference = new URL(new URL(baseWsdl),systemId); aoqi@0: systemId = reference.toExternalForm(); aoqi@0: } catch (MalformedURLException e) { aoqi@0: throw new RuntimeException(e); aoqi@0: } aoqi@0: if(documentMap.get(systemId) != null) { aoqi@0: return documentMap.get(systemId); aoqi@0: } else { aoqi@0: String parsedEntity = forest.getReferencedEntityMap().get(systemId); aoqi@0: return documentMap.get(parsedEntity); aoqi@0: } aoqi@0: } aoqi@0: }; aoqi@0: } aoqi@0: aoqi@0: private String sanitize(String fileName) { aoqi@0: fileName = fileName.replace('?', '.'); aoqi@0: StringBuilder sb = new StringBuilder(fileName); aoqi@0: for (int i = 0; i < sb.length(); i++) { aoqi@0: char c = sb.charAt(i); aoqi@0: if (Character.isLetterOrDigit(c) || aoqi@0: (c == '/') || aoqi@0: (c == '.') || aoqi@0: (c == '_') || aoqi@0: (c == ' ') || aoqi@0: (c == '-')) { aoqi@0: continue; aoqi@0: } else { aoqi@0: sb.setCharAt(i, '_'); aoqi@0: } aoqi@0: } aoqi@0: return sb.toString(); aoqi@0: } aoqi@0: aoqi@0: private File getWSDLDownloadDir() { aoqi@0: File wsdlDir = new File(options.destDir, WSDL_PATH); aoqi@0: boolean created = wsdlDir.mkdirs(); aoqi@0: if (options.verbose && !created) { aoqi@0: listener.message(WscompileMessages.WSCOMPILE_NO_SUCH_DIRECTORY(wsdlDir)); aoqi@0: } aoqi@0: return wsdlDir; aoqi@0: } aoqi@0: aoqi@0: private static String WSDL_PATH="META-INF/wsdl"; aoqi@0: private static String WSDL_FILE_EXTENSION=".wsdl"; aoqi@0: private static String SCHEMA_FILE_EXTENSION=".xsd"; aoqi@0: }