/* * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.tools.internal.ws.wscompile; import com.oracle.webservices.internal.api.databinding.WSDLResolver; import com.sun.tools.internal.ws.ToolVersion; import com.sun.tools.internal.ws.processor.modeler.annotation.WebServiceAp; import com.sun.tools.internal.ws.processor.modeler.wsdl.ConsoleErrorReporter; import com.sun.tools.internal.ws.resources.WscompileMessages; import com.sun.tools.internal.xjc.util.NullStream; import com.sun.xml.internal.txw2.TXW; import com.sun.xml.internal.txw2.TypedXmlWriter; import com.sun.xml.internal.txw2.annotation.XmlAttribute; import com.sun.xml.internal.txw2.annotation.XmlElement; import com.sun.xml.internal.txw2.output.StreamSerializer; import com.sun.xml.internal.ws.api.BindingID; import com.sun.xml.internal.ws.api.databinding.DatabindingConfig; import com.sun.xml.internal.ws.api.databinding.DatabindingFactory; import com.sun.xml.internal.ws.api.databinding.WSDLGenInfo; import com.sun.xml.internal.ws.api.server.Container; import com.sun.xml.internal.ws.api.wsdl.writer.WSDLGeneratorExtension; import com.sun.xml.internal.ws.binding.WebServiceFeatureList; import com.sun.xml.internal.ws.model.ExternalMetadataReader; import com.sun.xml.internal.ws.model.AbstractSEIModelImpl; import com.sun.xml.internal.ws.util.ServiceFinder; import org.xml.sax.SAXParseException; import javax.tools.DiagnosticCollector; import javax.tools.JavaCompiler; import javax.tools.JavaFileObject; import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; import javax.xml.namespace.QName; import javax.xml.transform.Result; import javax.xml.transform.stream.StreamResult; import javax.xml.ws.Holder; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @author Vivek Pandey */ /* * All annotation types are supported. */ public class WsgenTool { private final PrintStream out; private final WsgenOptions options = new WsgenOptions(); public WsgenTool(OutputStream out, Container container) { this.out = (out instanceof PrintStream) ? (PrintStream) out : new PrintStream(out); this.container = container; } public WsgenTool(OutputStream out) { this(out, null); } public boolean run(String[] args) { final Listener listener = new Listener(); for (String arg : args) { if (arg.equals("-version")) { listener.message( WscompileMessages.WSGEN_VERSION(ToolVersion.VERSION.MAJOR_VERSION)); return true; } if (arg.equals("-fullversion")) { listener.message( WscompileMessages.WSGEN_FULLVERSION(ToolVersion.VERSION.toString())); return true; } } try { options.parseArguments(args); options.validate(); if (!buildModel(options.endpoint.getName(), listener)) { return false; } } catch (Options.WeAreDone done) { usage(done.getOptions()); } catch (BadCommandLineException e) { if (e.getMessage() != null) { System.out.println(e.getMessage()); System.out.println(); } usage(e.getOptions()); return false; } catch (AbortException e) { //error might have been reported } finally { if (!options.keep) { options.removeGeneratedFiles(); } } return true; } private final Container container; /** * * @param endpoint * @param listener * @return * @throws BadCommandLineException */ public boolean buildModel(String endpoint, Listener listener) throws BadCommandLineException { final ErrorReceiverFilter errReceiver = new ErrorReceiverFilter(listener); List<String> args = new ArrayList<String>(6 + (options.nocompile ? 1 : 0) + (options.encoding != null ? 2 : 0)); args.add("--add-modules"); args.add("java.xml.ws"); args.add("-d"); args.add(options.destDir.getAbsolutePath()); args.add("-classpath"); args.add(options.classpath); args.add("-s"); args.add(options.sourceDir.getAbsolutePath()); if (options.nocompile) { args.add("-proc:only"); } if (options.encoding != null) { args.add("-encoding"); args.add(options.encoding); } if (options.javacOptions != null) { args.addAll(options.getJavacOptions(args, listener)); } JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); if (compiler == null) { out.println(WscompileMessages.WSCOMPILE_CANT_GET_COMPILER(property("java.home"), property("java.version"), property("java.vendor"))); return false; } DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>(); StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null); JavaCompiler.CompilationTask task = compiler.getTask( null, fileManager, diagnostics, args, Collections.singleton(endpoint.replaceAll("\\$", ".")), null); task.setProcessors(Collections.singleton(new WebServiceAp(options, out))); boolean result = task.call(); if (!result) { out.println(WscompileMessages.WSCOMPILE_ERROR(WscompileMessages.WSCOMPILE_COMPILATION_FAILED())); return false; } if (options.genWsdl) { DatabindingConfig config = new DatabindingConfig(); List<String> externalMetadataFileNames = options.externalMetadataFiles; boolean disableXmlSecurity = options.disableXmlSecurity; if (externalMetadataFileNames != null && externalMetadataFileNames.size() > 0) { config.setMetadataReader(new ExternalMetadataReader(getExternalFiles(externalMetadataFileNames), null, null, true, disableXmlSecurity)); } String tmpPath = options.destDir.getAbsolutePath() + File.pathSeparator + options.classpath; ClassLoader classLoader = new URLClassLoader(Options.pathToURLs(tmpPath), this.getClass().getClassLoader()); Class<?> endpointClass; try { endpointClass = classLoader.loadClass(endpoint); } catch (ClassNotFoundException e) { throw new BadCommandLineException(WscompileMessages.WSGEN_CLASS_NOT_FOUND(endpoint)); } BindingID bindingID = options.getBindingID(options.protocol); if (!options.protocolSet) { bindingID = BindingID.parse(endpointClass); } WebServiceFeatureList wsfeatures = new WebServiceFeatureList(endpointClass); // RuntimeModeler rtModeler = new RuntimeModeler(endpointClass, options.serviceName, bindingID, wsfeatures.toArray()); // rtModeler.setClassLoader(classLoader); if (options.portName != null) config.getMappingInfo().setPortName(options.portName);//rtModeler.setPortName(options.portName); // AbstractSEIModelImpl rtModel = rtModeler.buildRuntimeModel(); DatabindingFactory fac = DatabindingFactory.newInstance(); config.setEndpointClass(endpointClass); config.getMappingInfo().setServiceName(options.serviceName); config.setFeatures(wsfeatures.toArray()); config.setClassLoader(classLoader); config.getMappingInfo().setBindingID(bindingID); com.sun.xml.internal.ws.db.DatabindingImpl rt = (com.sun.xml.internal.ws.db.DatabindingImpl) fac.createRuntime(config); final File[] wsdlFileName = new File[1]; // used to capture the generated WSDL file. final Map<String, File> schemaFiles = new HashMap<String, File>(); WSDLGenInfo wsdlGenInfo = new WSDLGenInfo(); wsdlGenInfo.setSecureXmlProcessingDisabled(disableXmlSecurity); wsdlGenInfo.setWsdlResolver( new WSDLResolver() { private File toFile(String suggestedFilename) { return new File(options.nonclassDestDir, suggestedFilename); } private Result toResult(File file) { Result result; try { result = new StreamResult(new FileOutputStream(file)); result.setSystemId(file.getPath().replace('\\', '/')); } catch (FileNotFoundException e) { errReceiver.error(e); return null; } return result; } @Override public Result getWSDL(String suggestedFilename) { File f = toFile(suggestedFilename); wsdlFileName[0] = f; return toResult(f); } public Result getSchemaOutput(String namespace, String suggestedFilename) { if (namespace == null) return null; File f = toFile(suggestedFilename); schemaFiles.put(namespace, f); return toResult(f); } @Override public Result getAbstractWSDL(Holder<String> filename) { return toResult(toFile(filename.value)); } @Override public Result getSchemaOutput(String namespace, Holder<String> filename) { return getSchemaOutput(namespace, filename.value); } // TODO pass correct impl's class name }); wsdlGenInfo.setContainer(container); wsdlGenInfo.setExtensions(ServiceFinder.find(WSDLGeneratorExtension.class).toArray()); wsdlGenInfo.setInlineSchemas(options.inlineSchemas); rt.generateWSDL(wsdlGenInfo); if (options.wsgenReport != null) generateWsgenReport(endpointClass, (AbstractSEIModelImpl) rt.getModel(), wsdlFileName[0], schemaFiles); } return true; } private String property(String key) { try { String property = System.getProperty(key); return property != null ? property : "UNKNOWN"; } catch (SecurityException ignored) { return "UNKNOWN"; } } private List<File> getExternalFiles(List<String> exts) { List<File> files = new ArrayList<File>(); for (String ext : exts) { // first try absolute path ... File file = new File(ext); if (!file.exists()) { // then relative path ... file = new File(options.sourceDir.getAbsolutePath() + File.separator + ext); } files.add(file); } return files; } /** * Generates a small XML file that captures the key activity of wsgen, * so that test harness can pick up artifacts. */ private void generateWsgenReport(Class<?> endpointClass, AbstractSEIModelImpl rtModel, File wsdlFile, Map<String, File> schemaFiles) { try { ReportOutput.Report report = TXW.create(ReportOutput.Report.class, new StreamSerializer(new BufferedOutputStream(new FileOutputStream(options.wsgenReport)))); report.wsdl(wsdlFile.getAbsolutePath()); ReportOutput.writeQName(rtModel.getServiceQName(), report.service()); ReportOutput.writeQName(rtModel.getPortName(), report.port()); ReportOutput.writeQName(rtModel.getPortTypeName(), report.portType()); report.implClass(endpointClass.getName()); for (Map.Entry<String, File> e : schemaFiles.entrySet()) { ReportOutput.Schema s = report.schema(); s.ns(e.getKey()); s.location(e.getValue().getAbsolutePath()); } report.commit(); } catch (IOException e) { // this is code for the test, so we can be lousy in the error handling throw new Error(e); } } /** * "Namespace" for code needed to generate the report file. */ static class ReportOutput { @XmlElement("report") interface Report extends TypedXmlWriter { @XmlElement void wsdl(String file); // location of WSDL @XmlElement QualifiedName portType(); @XmlElement QualifiedName service(); @XmlElement QualifiedName port(); /** * Name of the class that has {@link javax.jws.WebService}. */ @XmlElement void implClass(String name); @XmlElement Schema schema(); } interface QualifiedName extends TypedXmlWriter { @XmlAttribute void uri(String ns); @XmlAttribute void localName(String localName); } interface Schema extends TypedXmlWriter { @XmlAttribute void ns(String ns); @XmlAttribute void location(String filePath); } private static void writeQName(QName n, QualifiedName w) { w.uri(n.getNamespaceURI()); w.localName(n.getLocalPart()); } } protected void usage(Options options) { // Just don't see any point in passing WsgenOptions // BadCommandLineException also shouldn't have options if (options == null) options = this.options; if (options instanceof WsgenOptions) { System.out.println(WscompileMessages.WSGEN_HELP("WSGEN", ((WsgenOptions)options).protocols, ((WsgenOptions)options).nonstdProtocols.keySet())); System.out.println(WscompileMessages.WSGEN_USAGE_EXTENSIONS()); System.out.println(WscompileMessages.WSGEN_USAGE_EXAMPLES()); } } class Listener extends WsimportListener { ConsoleErrorReporter cer = new ConsoleErrorReporter(out == null ? new PrintStream(new NullStream()) : out); @Override public void generatedFile(String fileName) { message(fileName); } @Override public void message(String msg) { out.println(msg); } @Override public void error(SAXParseException exception) { cer.error(exception); } @Override public void fatalError(SAXParseException exception) { cer.fatalError(exception); } @Override public void warning(SAXParseException exception) { cer.warning(exception); } @Override public void info(SAXParseException exception) { cer.info(exception); } } }