1 /* 2 * Copyright (c) 1997, 2016, 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.wscompile; 27 28 import com.oracle.webservices.internal.api.databinding.WSDLResolver; 29 import com.sun.tools.internal.ws.ToolVersion; 30 import com.sun.tools.internal.ws.processor.modeler.annotation.WebServiceAp; 31 import com.sun.tools.internal.ws.processor.modeler.wsdl.ConsoleErrorReporter; 32 import com.sun.tools.internal.ws.resources.WscompileMessages; 33 import com.sun.tools.internal.xjc.util.NullStream; 34 import com.sun.xml.internal.txw2.TXW; 35 import com.sun.xml.internal.txw2.TypedXmlWriter; 36 import com.sun.xml.internal.txw2.annotation.XmlAttribute; 37 import com.sun.xml.internal.txw2.annotation.XmlElement; 38 import com.sun.xml.internal.txw2.output.StreamSerializer; 39 import com.sun.xml.internal.ws.api.BindingID; 40 import com.sun.xml.internal.ws.api.databinding.DatabindingConfig; 41 import com.sun.xml.internal.ws.api.databinding.DatabindingFactory; 42 import com.sun.xml.internal.ws.api.databinding.WSDLGenInfo; 43 import com.sun.xml.internal.ws.api.server.Container; 44 import com.sun.xml.internal.ws.api.wsdl.writer.WSDLGeneratorExtension; 45 import com.sun.xml.internal.ws.binding.WebServiceFeatureList; 46 import com.sun.xml.internal.ws.model.ExternalMetadataReader; 47 import com.sun.xml.internal.ws.model.AbstractSEIModelImpl; 48 import com.sun.xml.internal.ws.util.ServiceFinder; 49 import org.xml.sax.SAXParseException; 50 51 import javax.tools.DiagnosticCollector; 52 import javax.tools.JavaCompiler; 53 import javax.tools.JavaFileObject; 54 import javax.tools.StandardJavaFileManager; 55 import javax.tools.ToolProvider; 56 import javax.xml.namespace.QName; 57 import javax.xml.transform.Result; 58 import javax.xml.transform.stream.StreamResult; 59 import javax.xml.ws.Holder; 60 import java.io.BufferedOutputStream; 61 import java.io.File; 62 import java.io.FileNotFoundException; 63 import java.io.FileOutputStream; 64 import java.io.IOException; 65 import java.io.OutputStream; 66 import java.io.PrintStream; 67 import java.net.URLClassLoader; 68 import java.util.ArrayList; 69 import java.util.Collections; 70 import java.util.HashMap; 71 import java.util.List; 72 import java.util.Map; 73 74 /** 75 * @author Vivek Pandey 76 */ 77 78 /* 79 * All annotation types are supported. 80 */ 81 public class WsgenTool { 82 private final PrintStream out; 83 private final WsgenOptions options = new WsgenOptions(); 84 85 86 public WsgenTool(OutputStream out, Container container) { 87 this.out = (out instanceof PrintStream) ? (PrintStream) out : new PrintStream(out); 88 this.container = container; 89 } 90 91 92 public WsgenTool(OutputStream out) { 93 this(out, null); 94 } 95 96 public boolean run(String[] args) { 97 final Listener listener = new Listener(); 98 for (String arg : args) { 99 if (arg.equals("-version")) { 100 listener.message( 101 WscompileMessages.WSGEN_VERSION(ToolVersion.VERSION.MAJOR_VERSION)); 102 return true; 103 } 104 if (arg.equals("-fullversion")) { 105 listener.message( 106 WscompileMessages.WSGEN_FULLVERSION(ToolVersion.VERSION.toString())); 107 return true; 108 } 109 } 110 try { 111 options.parseArguments(args); 112 options.validate(); 113 if (!buildModel(options.endpoint.getName(), listener)) { 114 return false; 115 } 116 } catch (Options.WeAreDone done) { 117 usage(done.getOptions()); 118 } catch (BadCommandLineException e) { 119 if (e.getMessage() != null) { 120 System.out.println(e.getMessage()); 121 System.out.println(); 122 } 123 usage(e.getOptions()); 124 return false; 125 } catch (AbortException e) { 126 //error might have been reported 127 } finally { 128 if (!options.keep) { 129 options.removeGeneratedFiles(); 130 } 131 } 132 return true; 133 } 134 135 private final Container container; 136 137 /** 138 * 139 * @param endpoint 140 * @param listener 141 * @return 142 * @throws BadCommandLineException 143 */ 144 public boolean buildModel(String endpoint, Listener listener) throws BadCommandLineException { 145 final ErrorReceiverFilter errReceiver = new ErrorReceiverFilter(listener); 146 147 List<String> args = new ArrayList<String>(6 + (options.nocompile ? 1 : 0) 148 + (options.encoding != null ? 2 : 0)); 149 150 args.add("--add-modules"); 151 args.add("java.xml.ws"); 152 153 args.add("-d"); 154 args.add(options.destDir.getAbsolutePath()); 155 args.add("-classpath"); 156 args.add(options.classpath); 157 args.add("-s"); 158 args.add(options.sourceDir.getAbsolutePath()); 159 if (options.nocompile) { 160 args.add("-proc:only"); 161 } 162 if (options.encoding != null) { 163 args.add("-encoding"); 164 args.add(options.encoding); 165 } 166 if (options.javacOptions != null) { 167 args.addAll(options.getJavacOptions(args, listener)); 168 } 169 170 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 171 if (compiler == null) { 172 out.println(WscompileMessages.WSCOMPILE_CANT_GET_COMPILER(property("java.home"), property("java.version"), property("java.vendor"))); 173 return false; 174 } 175 DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>(); 176 StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null); 177 JavaCompiler.CompilationTask task = compiler.getTask( 178 null, 179 fileManager, 180 diagnostics, 181 args, 182 Collections.singleton(endpoint.replaceAll("\\$", ".")), 183 null); 184 task.setProcessors(Collections.singleton(new WebServiceAp(options, out))); 185 boolean result = task.call(); 186 187 if (!result) { 188 out.println(WscompileMessages.WSCOMPILE_ERROR(WscompileMessages.WSCOMPILE_COMPILATION_FAILED())); 189 return false; 190 } 191 if (options.genWsdl) { 192 DatabindingConfig config = new DatabindingConfig(); 193 194 List<String> externalMetadataFileNames = options.externalMetadataFiles; 195 boolean disableXmlSecurity = options.disableXmlSecurity; 196 if (externalMetadataFileNames != null && externalMetadataFileNames.size() > 0) { 197 config.setMetadataReader(new ExternalMetadataReader(getExternalFiles(externalMetadataFileNames), null, null, true, disableXmlSecurity)); 198 } 199 200 String tmpPath = options.destDir.getAbsolutePath() + File.pathSeparator + options.classpath; 201 ClassLoader classLoader = new URLClassLoader(Options.pathToURLs(tmpPath), 202 this.getClass().getClassLoader()); 203 Class<?> endpointClass; 204 try { 205 endpointClass = classLoader.loadClass(endpoint); 206 } catch (ClassNotFoundException e) { 207 throw new BadCommandLineException(WscompileMessages.WSGEN_CLASS_NOT_FOUND(endpoint)); 208 } 209 210 BindingID bindingID = options.getBindingID(options.protocol); 211 if (!options.protocolSet) { 212 bindingID = BindingID.parse(endpointClass); 213 } 214 WebServiceFeatureList wsfeatures = new WebServiceFeatureList(endpointClass); 215 // RuntimeModeler rtModeler = new RuntimeModeler(endpointClass, options.serviceName, bindingID, wsfeatures.toArray()); 216 // rtModeler.setClassLoader(classLoader); 217 if (options.portName != null) 218 config.getMappingInfo().setPortName(options.portName);//rtModeler.setPortName(options.portName); 219 // AbstractSEIModelImpl rtModel = rtModeler.buildRuntimeModel(); 220 221 DatabindingFactory fac = DatabindingFactory.newInstance(); 222 config.setEndpointClass(endpointClass); 223 config.getMappingInfo().setServiceName(options.serviceName); 224 config.setFeatures(wsfeatures.toArray()); 225 config.setClassLoader(classLoader); 226 config.getMappingInfo().setBindingID(bindingID); 227 com.sun.xml.internal.ws.db.DatabindingImpl rt = (com.sun.xml.internal.ws.db.DatabindingImpl) fac.createRuntime(config); 228 229 final File[] wsdlFileName = new File[1]; // used to capture the generated WSDL file. 230 final Map<String, File> schemaFiles = new HashMap<String, File>(); 231 232 WSDLGenInfo wsdlGenInfo = new WSDLGenInfo(); 233 wsdlGenInfo.setSecureXmlProcessingDisabled(disableXmlSecurity); 234 235 wsdlGenInfo.setWsdlResolver( 236 new WSDLResolver() { 237 private File toFile(String suggestedFilename) { 238 return new File(options.nonclassDestDir, suggestedFilename); 239 } 240 241 private Result toResult(File file) { 242 Result result; 243 try { 244 result = new StreamResult(new FileOutputStream(file)); 245 result.setSystemId(file.getPath().replace('\\', '/')); 246 } catch (FileNotFoundException e) { 247 errReceiver.error(e); 248 return null; 249 } 250 return result; 251 } 252 253 @Override 254 public Result getWSDL(String suggestedFilename) { 255 File f = toFile(suggestedFilename); 256 wsdlFileName[0] = f; 257 return toResult(f); 258 } 259 260 public Result getSchemaOutput(String namespace, String suggestedFilename) { 261 if (namespace == null) 262 return null; 263 File f = toFile(suggestedFilename); 264 schemaFiles.put(namespace, f); 265 return toResult(f); 266 } 267 268 @Override 269 public Result getAbstractWSDL(Holder<String> filename) { 270 return toResult(toFile(filename.value)); 271 } 272 273 @Override 274 public Result getSchemaOutput(String namespace, Holder<String> filename) { 275 return getSchemaOutput(namespace, filename.value); 276 } 277 // TODO pass correct impl's class name 278 }); 279 280 wsdlGenInfo.setContainer(container); 281 wsdlGenInfo.setExtensions(ServiceFinder.find(WSDLGeneratorExtension.class).toArray()); 282 wsdlGenInfo.setInlineSchemas(options.inlineSchemas); 283 rt.generateWSDL(wsdlGenInfo); 284 285 286 if (options.wsgenReport != null) 287 generateWsgenReport(endpointClass, (AbstractSEIModelImpl) rt.getModel(), wsdlFileName[0], schemaFiles); 288 } 289 return true; 290 } 291 292 private String property(String key) { 293 try { 294 String property = System.getProperty(key); 295 return property != null ? property : "UNKNOWN"; 296 } catch (SecurityException ignored) { 297 return "UNKNOWN"; 298 } 299 } 300 301 private List<File> getExternalFiles(List<String> exts) { 302 List<File> files = new ArrayList<File>(); 303 for (String ext : exts) { 304 // first try absolute path ... 305 File file = new File(ext); 306 if (!file.exists()) { 307 // then relative path ... 308 file = new File(options.sourceDir.getAbsolutePath() + File.separator + ext); 309 } 310 files.add(file); 311 } 312 return files; 313 } 314 315 /** 316 * Generates a small XML file that captures the key activity of wsgen, 317 * so that test harness can pick up artifacts. 318 */ 319 private void generateWsgenReport(Class<?> endpointClass, AbstractSEIModelImpl rtModel, File wsdlFile, Map<String, File> schemaFiles) { 320 try { 321 ReportOutput.Report report = TXW.create(ReportOutput.Report.class, 322 new StreamSerializer(new BufferedOutputStream(new FileOutputStream(options.wsgenReport)))); 323 324 report.wsdl(wsdlFile.getAbsolutePath()); 325 ReportOutput.writeQName(rtModel.getServiceQName(), report.service()); 326 ReportOutput.writeQName(rtModel.getPortName(), report.port()); 327 ReportOutput.writeQName(rtModel.getPortTypeName(), report.portType()); 328 329 report.implClass(endpointClass.getName()); 330 331 for (Map.Entry<String, File> e : schemaFiles.entrySet()) { 332 ReportOutput.Schema s = report.schema(); 333 s.ns(e.getKey()); 334 s.location(e.getValue().getAbsolutePath()); 335 } 336 337 report.commit(); 338 } catch (IOException e) { 339 // this is code for the test, so we can be lousy in the error handling 340 throw new Error(e); 341 } 342 } 343 344 /** 345 * "Namespace" for code needed to generate the report file. 346 */ 347 static class ReportOutput { 348 @XmlElement("report") 349 interface Report extends TypedXmlWriter { 350 @XmlElement 351 void wsdl(String file); // location of WSDL 352 353 @XmlElement 354 QualifiedName portType(); 355 356 @XmlElement 357 QualifiedName service(); 358 359 @XmlElement 360 QualifiedName port(); 361 362 /** 363 * Name of the class that has {@link javax.jws.WebService}. 364 */ 365 @XmlElement 366 void implClass(String name); 367 368 @XmlElement 369 Schema schema(); 370 } 371 372 interface QualifiedName extends TypedXmlWriter { 373 @XmlAttribute 374 void uri(String ns); 375 376 @XmlAttribute 377 void localName(String localName); 378 } 379 380 interface Schema extends TypedXmlWriter { 381 @XmlAttribute 382 void ns(String ns); 383 384 @XmlAttribute 385 void location(String filePath); 386 } 387 388 private static void writeQName(QName n, QualifiedName w) { 389 w.uri(n.getNamespaceURI()); 390 w.localName(n.getLocalPart()); 391 } 392 } 393 394 protected void usage(Options options) { 395 // Just don't see any point in passing WsgenOptions 396 // BadCommandLineException also shouldn't have options 397 if (options == null) 398 options = this.options; 399 if (options instanceof WsgenOptions) { 400 System.out.println(WscompileMessages.WSGEN_HELP("WSGEN", 401 ((WsgenOptions)options).protocols, 402 ((WsgenOptions)options).nonstdProtocols.keySet())); 403 System.out.println(WscompileMessages.WSGEN_USAGE_EXTENSIONS()); 404 System.out.println(WscompileMessages.WSGEN_USAGE_EXAMPLES()); 405 } 406 } 407 408 class Listener extends WsimportListener { 409 ConsoleErrorReporter cer = new ConsoleErrorReporter(out == null ? new PrintStream(new NullStream()) : out); 410 411 @Override 412 public void generatedFile(String fileName) { 413 message(fileName); 414 } 415 416 @Override 417 public void message(String msg) { 418 out.println(msg); 419 } 420 421 @Override 422 public void error(SAXParseException exception) { 423 cer.error(exception); 424 } 425 426 @Override 427 public void fatalError(SAXParseException exception) { 428 cer.fatalError(exception); 429 } 430 431 @Override 432 public void warning(SAXParseException exception) { 433 cer.warning(exception); 434 } 435 436 @Override 437 public void info(SAXParseException exception) { 438 cer.info(exception); 439 } 440 } 441 }