1 /* 2 * Copyright (c) 1997, 2014, 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.sun.codemodel.internal.CodeWriter; 29 import com.sun.codemodel.internal.writer.ProgressCodeWriter; 30 import com.sun.istack.internal.tools.DefaultAuthenticator; 31 import com.sun.tools.internal.ws.ToolVersion; 32 import com.sun.tools.internal.ws.api.TJavaGeneratorExtension; 33 import com.sun.tools.internal.ws.processor.generator.CustomExceptionGenerator; 34 import com.sun.tools.internal.ws.processor.generator.GeneratorBase; 35 import com.sun.tools.internal.ws.processor.generator.SeiGenerator; 36 import com.sun.tools.internal.ws.processor.generator.ServiceGenerator; 37 import com.sun.tools.internal.ws.processor.generator.JwsImplGenerator; 38 import com.sun.tools.internal.ws.processor.model.Model; 39 import com.sun.tools.internal.ws.processor.modeler.wsdl.ConsoleErrorReporter; 40 import com.sun.tools.internal.ws.processor.modeler.wsdl.WSDLModeler; 41 import com.sun.tools.internal.ws.processor.util.DirectoryUtil; 42 import com.sun.tools.internal.ws.resources.WscompileMessages; 43 import com.sun.tools.internal.ws.resources.WsdlMessages; 44 import com.sun.tools.internal.ws.util.WSDLFetcher; 45 import com.sun.tools.internal.ws.wsdl.parser.MetadataFinder; 46 import com.sun.tools.internal.ws.wsdl.parser.WSDLInternalizationLogic; 47 import com.sun.tools.internal.xjc.util.NullStream; 48 import com.sun.xml.internal.ws.api.server.Container; 49 import com.sun.xml.internal.ws.util.ServiceFinder; 50 import com.sun.istack.internal.tools.ParallelWorldClassLoader; 51 import org.xml.sax.EntityResolver; 52 import org.xml.sax.SAXParseException; 53 54 import javax.xml.bind.JAXBPermission; 55 import javax.xml.stream.*; 56 import javax.xml.ws.EndpointContext; 57 import java.io.*; 58 import java.util.*; 59 import java.text.MessageFormat; 60 import java.util.jar.JarEntry; 61 import java.util.jar.JarOutputStream; 62 import org.xml.sax.Locator; 63 import org.xml.sax.SAXException; 64 65 /** 66 * @author Vivek Pandey 67 */ 68 public class WsimportTool { 69 private static final String WSIMPORT = "wsimport"; 70 private final PrintStream out; 71 private final Container container; 72 73 /** 74 * Wsimport specific options 75 */ 76 protected WsimportOptions options = new WsimportOptions(); 77 78 public WsimportTool(OutputStream out) { 79 this(out, null); 80 } 81 82 public WsimportTool(OutputStream logStream, Container container) { 83 this.out = (logStream instanceof PrintStream)?(PrintStream)logStream:new PrintStream(logStream); 84 this.container = container; 85 } 86 87 protected class Listener extends WsimportListener { 88 ConsoleErrorReporter cer = new ConsoleErrorReporter(out == null ? new PrintStream(new NullStream()) : out); 89 90 @Override 91 public void generatedFile(String fileName) { 92 message(fileName); 93 } 94 95 @Override 96 public void message(String msg) { 97 out.println(msg); 98 } 99 100 @Override 101 public void error(SAXParseException exception) { 102 cer.error(exception); 103 } 104 105 @Override 106 public void fatalError(SAXParseException exception) { 107 cer.fatalError(exception); 108 } 109 110 @Override 111 public void warning(SAXParseException exception) { 112 cer.warning(exception); 113 } 114 115 @Override 116 public void debug(SAXParseException exception) { 117 cer.debug(exception); 118 } 119 120 @Override 121 public void info(SAXParseException exception) { 122 cer.info(exception); 123 } 124 125 public void enableDebugging(){ 126 cer.enableDebugging(); 127 } 128 } 129 130 protected class Receiver extends ErrorReceiverFilter { 131 132 private Listener listener; 133 134 public Receiver(Listener listener) { 135 super(listener); 136 this.listener = listener; 137 } 138 139 @Override 140 public void info(SAXParseException exception) { 141 if (options.verbose) 142 super.info(exception); 143 } 144 145 @Override 146 public void warning(SAXParseException exception) { 147 if (!options.quiet) 148 super.warning(exception); 149 } 150 151 @Override 152 public void pollAbort() throws AbortException { 153 if (listener.isCanceled()) 154 throw new AbortException(); 155 } 156 157 @Override 158 public void debug(SAXParseException exception){ 159 if(options.debugMode){ 160 listener.debug(exception); 161 } 162 } 163 } 164 165 public boolean run(String[] args) { 166 Listener listener = new Listener(); 167 Receiver receiver = new Receiver(listener); 168 return run(args, listener, receiver); 169 } 170 171 protected boolean run(String[] args, Listener listener, 172 Receiver receiver) { 173 for (String arg : args) { 174 if (arg.equals("-version")) { 175 listener.message( 176 WscompileMessages.WSIMPORT_VERSION(ToolVersion.VERSION.MAJOR_VERSION)); 177 return true; 178 } 179 if (arg.equals("-fullversion")) { 180 listener.message( 181 WscompileMessages.WSIMPORT_FULLVERSION(ToolVersion.VERSION.toString())); 182 return true; 183 } 184 } 185 186 try { 187 parseArguments(args, listener, receiver); 188 189 try { 190 Model wsdlModel = buildWsdlModel(listener, receiver); 191 if (wsdlModel == null) 192 return false; 193 194 if (!generateCode(listener, receiver, wsdlModel, true)) 195 return false; 196 197 /* Not so fast! 198 } catch(AbortException e){ 199 //error might have been reported 200 * 201 */ 202 }catch (IOException e) { 203 receiver.error(e); 204 return false; 205 }catch (XMLStreamException e) { 206 receiver.error(e); 207 return false; 208 } 209 if (!options.nocompile){ 210 if(!compileGeneratedClasses(receiver, listener)){ 211 listener.message(WscompileMessages.WSCOMPILE_COMPILATION_FAILED()); 212 return false; 213 } 214 } 215 try { 216 if (options.clientjar != null) { 217 //add all the generated class files to the list of generated files 218 addClassesToGeneratedFiles(); 219 jarArtifacts(listener); 220 221 } 222 } catch (IOException e) { 223 receiver.error(e); 224 return false; 225 } 226 227 } catch (Options.WeAreDone done) { 228 usage(done.getOptions()); 229 } catch (BadCommandLineException e) { 230 if (e.getMessage() != null) { 231 System.out.println(e.getMessage()); 232 System.out.println(); 233 } 234 usage(e.getOptions()); 235 return false; 236 } finally{ 237 deleteGeneratedFiles(); 238 if (!options.disableAuthenticator) { 239 DefaultAuthenticator.reset(); 240 } 241 } 242 if(receiver.hadError()) { 243 return false; 244 } 245 return true; 246 } 247 248 private void deleteGeneratedFiles() { 249 Set<File> trackedRootPackages = new HashSet<File>(); 250 251 if (options.clientjar != null) { 252 //remove all non-java artifacts as they will packaged in jar. 253 Iterable<File> generatedFiles = options.getGeneratedFiles(); 254 synchronized (generatedFiles) { 255 for (File file : generatedFiles) { 256 if (!file.getName().endsWith(".java")) { 257 boolean deleted = file.delete(); 258 if (options.verbose && !deleted) { 259 System.out.println(MessageFormat.format("{0} could not be deleted.", file)); 260 } 261 trackedRootPackages.add(file.getParentFile()); 262 } 263 } 264 } 265 //remove empty package dirs 266 for(File pkg:trackedRootPackages) { 267 268 while(pkg.list() != null && pkg.list().length ==0 && !pkg.equals(options.destDir)) { 269 File parentPkg = pkg.getParentFile(); 270 boolean deleted = pkg.delete(); 271 if (options.verbose && !deleted) { 272 System.out.println(MessageFormat.format("{0} could not be deleted.", pkg)); 273 } 274 pkg = parentPkg; 275 } 276 } 277 } 278 if(!options.keep) { 279 options.removeGeneratedFiles(); 280 } 281 } 282 283 private void addClassesToGeneratedFiles() throws IOException { 284 Iterable<File> generatedFiles = options.getGeneratedFiles(); 285 final List<File> trackedClassFiles = new ArrayList<File>(); 286 for(File f: generatedFiles) { 287 if(f.getName().endsWith(".java")) { 288 String relativeDir = DirectoryUtil.getRelativePathfromCommonBase(f.getParentFile(),options.sourceDir); 289 final String className = f.getName().substring(0,f.getName().indexOf(".java")); 290 File classDir = new File(options.destDir,relativeDir); 291 if(classDir.exists()) { 292 classDir.listFiles(new FilenameFilter() { 293 @Override 294 public boolean accept(File dir, String name) { 295 if(name.equals(className+".class") || (name.startsWith(className+"$") && name.endsWith(".class"))) { 296 trackedClassFiles.add(new File(dir,name)); 297 return true; 298 } 299 return false; 300 } 301 }); 302 } 303 } 304 } 305 for(File f: trackedClassFiles) { 306 options.addGeneratedFile(f); 307 } 308 } 309 310 private void jarArtifacts(WsimportListener listener) throws IOException { 311 File zipFile = new File(options.clientjar); 312 if(!zipFile.isAbsolute()) { 313 zipFile = new File(options.destDir, options.clientjar); 314 } 315 316 FileOutputStream fos; 317 if (!options.quiet) { 318 listener.message(WscompileMessages.WSIMPORT_ARCHIVING_ARTIFACTS(zipFile)); 319 } 320 321 BufferedInputStream bis = null; 322 FileInputStream fi = null; 323 fos = new FileOutputStream(zipFile); 324 JarOutputStream jos = new JarOutputStream(fos); 325 try { 326 String base = options.destDir.getCanonicalPath(); 327 for(File f: options.getGeneratedFiles()) { 328 //exclude packaging the java files in the jar 329 if(f.getName().endsWith(".java")) { 330 continue; 331 } 332 if(options.verbose) { 333 listener.message(WscompileMessages.WSIMPORT_ARCHIVE_ARTIFACT(f, options.clientjar)); 334 } 335 String entry = f.getCanonicalPath().substring(base.length()+1).replace(File.separatorChar, '/'); 336 fi = new FileInputStream(f); 337 bis = new BufferedInputStream(fi); 338 JarEntry jarEntry = new JarEntry(entry); 339 jos.putNextEntry(jarEntry); 340 int bytesRead; 341 byte[] buffer = new byte[1024]; 342 while ((bytesRead = bis.read(buffer)) != -1) { 343 jos.write(buffer, 0, bytesRead); 344 } 345 } 346 } finally { 347 try { 348 if (bis != null) { 349 bis.close(); 350 } 351 } finally { 352 if (jos != null) { 353 jos.close(); 354 } 355 if (fi != null) { 356 fi.close(); 357 } 358 } 359 } 360 } 361 362 protected void parseArguments(String[] args, Listener listener, 363 Receiver receiver) throws BadCommandLineException { 364 options.parseArguments(args); 365 options.validate(); 366 if (options.debugMode) 367 listener.enableDebugging(); 368 options.parseBindings(receiver); 369 } 370 371 protected Model buildWsdlModel(Listener listener, final Receiver receiver) 372 throws BadCommandLineException, XMLStreamException, IOException { 373 //set auth info 374 //if(options.authFile != null) 375 if (!options.disableAuthenticator) { 376 class AuthListener implements DefaultAuthenticator.Receiver { 377 378 private final boolean isFatal; 379 380 AuthListener(boolean isFatal) { 381 this.isFatal = isFatal; 382 } 383 384 @Override 385 public void onParsingError(String text, Locator loc) { 386 error(new SAXParseException(WscompileMessages.WSIMPORT_ILLEGAL_AUTH_INFO(text), loc)); 387 } 388 389 @Override 390 public void onError(Exception e, Locator loc) { 391 if (e instanceof FileNotFoundException) { 392 error(new SAXParseException(WscompileMessages.WSIMPORT_AUTH_FILE_NOT_FOUND( 393 loc.getSystemId(), WsimportOptions.defaultAuthfile), null)); 394 } else { 395 error(new SAXParseException(WscompileMessages.WSIMPORT_FAILED_TO_PARSE(loc.getSystemId(),e.getMessage()), loc)); 396 } 397 } 398 399 private void error(SAXParseException e) { 400 if (isFatal) { 401 receiver.error(e); 402 } else { 403 receiver.debug(e); 404 } 405 } 406 } 407 408 DefaultAuthenticator da = DefaultAuthenticator.getAuthenticator(); 409 if (options.proxyAuth != null) { 410 da.setProxyAuth(options.proxyAuth); 411 } 412 if (options.authFile != null) { 413 da.setAuth(options.authFile, new AuthListener(true)); 414 } else { 415 da.setAuth(new File(WsimportOptions.defaultAuthfile), new AuthListener(false)); 416 } 417 } 418 419 if (!options.quiet) { 420 listener.message(WscompileMessages.WSIMPORT_PARSING_WSDL()); 421 } 422 423 MetadataFinder forest = new MetadataFinder(new WSDLInternalizationLogic(), options, receiver); 424 forest.parseWSDL(); 425 if (forest.isMexMetadata) 426 receiver.reset(); 427 428 WSDLModeler wsdlModeler = new WSDLModeler(options, receiver,forest); 429 Model wsdlModel = wsdlModeler.buildModel(); 430 if (wsdlModel == null) { 431 listener.message(WsdlMessages.PARSING_PARSE_FAILED()); 432 } 433 434 if(options.clientjar != null) { 435 if( !options.quiet ) 436 listener.message(WscompileMessages.WSIMPORT_FETCHING_METADATA()); 437 options.wsdlLocation = new WSDLFetcher(options,listener).fetchWsdls(forest); 438 } 439 440 return wsdlModel; 441 } 442 443 protected boolean generateCode(Listener listener, Receiver receiver, 444 Model wsdlModel, boolean generateService) 445 throws IOException { 446 //generated code 447 if( !options.quiet ) 448 listener.message(WscompileMessages.WSIMPORT_GENERATING_CODE()); 449 450 TJavaGeneratorExtension[] genExtn = ServiceFinder.find(TJavaGeneratorExtension.class).toArray(); 451 CustomExceptionGenerator.generate(wsdlModel, options, receiver); 452 SeiGenerator.generate(wsdlModel, options, receiver, genExtn); 453 if(receiver.hadError()){ 454 throw new AbortException(); 455 } 456 if (generateService) 457 { 458 ServiceGenerator.generate(wsdlModel, options, receiver); 459 } 460 for (GeneratorBase g : ServiceFinder.find(GeneratorBase.class)) { 461 g.init(wsdlModel, options, receiver); 462 g.doGeneration(); 463 } 464 465 List<String> implFiles = null; 466 if (options.isGenerateJWS) { 467 implFiles = JwsImplGenerator.generate(wsdlModel, options, receiver); 468 } 469 470 for (Plugin plugin: options.activePlugins) { 471 try { 472 plugin.run(wsdlModel, options, receiver); 473 } catch (SAXException sex) { 474 // fatal error. error should have been reported 475 return false; 476 } 477 } 478 479 CodeWriter cw; 480 if (options.filer != null) { 481 cw = new FilerCodeWriter(options.sourceDir, options); 482 } else { 483 cw = new WSCodeWriter(options.sourceDir, options); 484 } 485 486 if (options.verbose) 487 cw = new ProgressCodeWriter(cw, out); 488 options.getCodeModel().build(cw); 489 490 if (options.isGenerateJWS) { 491 //move Impl files to implDestDir 492 return JwsImplGenerator.moveToImplDestDir(implFiles, options, receiver); 493 } 494 495 return true; 496 } 497 498 public void setEntityResolver(EntityResolver resolver){ 499 this.options.entityResolver = resolver; 500 } 501 502 /* 503 * To take care of JDK6-JDK6u3, where 2.1 API classes are not there 504 */ 505 private static boolean useBootClasspath(Class clazz) { 506 try { 507 ParallelWorldClassLoader.toJarUrl(clazz.getResource('/'+clazz.getName().replace('.','/')+".class")); 508 return true; 509 } catch(Exception e) { 510 return false; 511 } 512 } 513 514 protected boolean compileGeneratedClasses(ErrorReceiver receiver, WsimportListener listener){ 515 List<String> sourceFiles = new ArrayList<String>(); 516 517 for (File f : options.getGeneratedFiles()) { 518 if (f.exists() && f.getName().endsWith(".java")) { 519 sourceFiles.add(f.getAbsolutePath()); 520 } 521 } 522 523 if (sourceFiles.size() > 0) { 524 String classDir = options.destDir.getAbsolutePath(); 525 String classpathString = createClasspathString(); 526 boolean bootCP = useBootClasspath(EndpointContext.class) || useBootClasspath(JAXBPermission.class); 527 List<String> args = new ArrayList<String>(); 528 args.add("-addmods"); 529 args.add("java.xml.ws"); 530 args.add("-d"); 531 args.add(classDir); 532 args.add("-classpath"); 533 args.add(classpathString); 534 //javac is not working in osgi as the url starts with a bundle 535 if (bootCP) { 536 args.add("-Xbootclasspath/p:" 537 + JavaCompilerHelper.getJarFile(EndpointContext.class) 538 + File.pathSeparator 539 + JavaCompilerHelper.getJarFile(JAXBPermission.class)); 540 } 541 542 if (options.debug) { 543 args.add("-g"); 544 } 545 546 if (options.encoding != null) { 547 args.add("-encoding"); 548 args.add(options.encoding); 549 } 550 551 if (options.javacOptions != null) { 552 args.addAll(options.getJavacOptions(args, listener)); 553 } 554 555 for (int i = 0; i < sourceFiles.size(); ++i) { 556 args.add(sourceFiles.get(i)); 557 } 558 559 if (!options.quiet) listener.message(WscompileMessages.WSIMPORT_COMPILING_CODE()); 560 561 if(options.verbose){ 562 StringBuilder argstr = new StringBuilder(); 563 for(String arg:args){ 564 argstr.append(arg).append(" "); 565 } 566 listener.message("javac "+ argstr.toString()); 567 } 568 569 return JavaCompilerHelper.compile(args.toArray(new String[args.size()]), out, receiver); 570 } 571 //there are no files to compile, so return true? 572 return true; 573 } 574 575 private String createClasspathString() { 576 StringBuilder classpathStr = new StringBuilder(System.getProperty("java.class.path")); 577 for(String s: options.cmdlineJars) { 578 classpathStr.append(File.pathSeparator); 579 classpathStr.append(new File(s).toString()); 580 } 581 return classpathStr.toString(); 582 } 583 584 protected void usage(Options options) { 585 System.out.println(WscompileMessages.WSIMPORT_HELP(WSIMPORT)); 586 System.out.println(WscompileMessages.WSIMPORT_USAGE_EXTENSIONS()); 587 System.out.println(WscompileMessages.WSIMPORT_USAGE_EXAMPLES()); 588 } 589 }