1 /* 2 * Copyright (c) 1997, 2015, 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.tools.internal.ws.resources.WscompileMessages; 29 import com.sun.tools.internal.ws.Invoker; 30 31 import javax.annotation.processing.Filer; 32 import java.io.File; 33 import java.io.IOException; 34 import java.net.MalformedURLException; 35 import java.net.URL; 36 import java.net.URLClassLoader; 37 import java.nio.charset.Charset; 38 import java.nio.charset.IllegalCharsetNameException; 39 import java.text.MessageFormat; 40 import java.util.ArrayList; 41 import java.util.List; 42 import java.util.StringTokenizer; 43 44 /** 45 * Provide common jaxws tool options. 46 * 47 * @author Vivek Pandey 48 */ 49 public class Options { 50 /** 51 * -verbose 52 */ 53 public boolean verbose; 54 55 /** 56 * - quite 57 */ 58 public boolean quiet; 59 60 /** 61 * -keep 62 */ 63 public boolean keep; 64 65 66 67 /** 68 * -d 69 */ 70 public File destDir = new File("."); 71 72 73 /** 74 * -s 75 */ 76 public File sourceDir; 77 78 /** 79 * The filer that can use used to write out the generated files 80 */ 81 public Filer filer; 82 83 /** 84 * -encoding 85 */ 86 public String encoding; 87 88 public String classpath = System.getProperty("java.class.path"); 89 90 /** 91 * -javacOptions 92 * 93 * @since 2.2.9 94 */ 95 public List<String> javacOptions; 96 97 98 /** 99 * -Xnocompile 100 */ 101 public boolean nocompile; 102 103 /** 104 * If true XML security features when parsing XML documents will be disabled. 105 * The default value is false. 106 * 107 * Boolean 108 * @since 2.2.9 109 */ 110 public boolean disableXmlSecurity; 111 112 public enum Target { 113 V2_0, V2_1, V2_2; 114 115 /** 116 * Returns true if this version is equal or later than the given one. 117 */ 118 public boolean isLaterThan(Target t) { 119 return this.ordinal() >= t.ordinal(); 120 } 121 122 /** 123 * Parses "2.0" and "2.1" into the {@link Target} object. 124 * 125 * @return null for parsing failure. 126 */ 127 public static Target parse(String token) { 128 if (token.equals("2.0")) 129 return Target.V2_0; 130 else if (token.equals("2.1")) 131 return Target.V2_1; 132 else if (token.equals("2.2")) 133 return Target.V2_2; 134 return null; 135 } 136 137 /** 138 * Gives the String representation of the {@link Target} 139 */ 140 public String getVersion(){ 141 switch(this){ 142 case V2_0: 143 return "2.0"; 144 case V2_1: 145 return "2.1"; 146 case V2_2: 147 return "2.2"; 148 default: 149 return null; 150 } 151 } 152 153 public static Target getDefault() { 154 return V2_2; 155 } 156 157 public static Target getLoadedAPIVersion() { 158 return LOADED_API_VERSION; 159 } 160 161 private static final Target LOADED_API_VERSION; 162 163 static { 164 // check if we are indeed loading JAX-WS 2.2 API 165 if (Invoker.checkIfLoading22API()) { 166 LOADED_API_VERSION = Target.V2_2; 167 } // check if we are indeed loading JAX-WS 2.1 API 168 else if (Invoker.checkIfLoading21API()) { 169 LOADED_API_VERSION = Target.V2_1; 170 } else { 171 LOADED_API_VERSION = Target.V2_0; 172 } 173 } 174 } 175 176 public Target target = Target.V2_2; 177 178 /** 179 * Type of input schema language. One of the {@code SCHEMA_XXX} 180 * strictly follow the compatibility rules specified in JAXWS spec 181 */ 182 public static final int STRICT = 1; 183 184 /** 185 * loosely follow the compatibility rules and allow the use of vendor 186 * binding extensions 187 */ 188 public static final int EXTENSION = 2; 189 190 /** 191 * this switch determines how carefully the compiler will follow 192 * the compatibility rules in the spec. Either {@code STRICT} 193 * or {@code EXTENSION}. 194 */ 195 public int compatibilityMode = STRICT; 196 197 public boolean isExtensionMode() { 198 return compatibilityMode == EXTENSION; 199 } 200 201 public boolean debug = false; 202 203 /** 204 * -Xdebug - gives complete stack trace 205 */ 206 public boolean debugMode = false; 207 208 209 private final List<File> generatedFiles = new ArrayList<File>(); 210 private ClassLoader classLoader; 211 212 213 /** 214 * Remember info on generated source file generated so that it 215 * can be removed later, if appropriate. 216 */ 217 public void addGeneratedFile(File file) { 218 generatedFiles.add(file); 219 } 220 221 /** 222 * Remove generated files 223 */ 224 public void removeGeneratedFiles(){ 225 for(File file : generatedFiles){ 226 if (file.getName().endsWith(".java")) { 227 boolean deleted = file.delete(); 228 if (verbose && !deleted) { 229 System.out.println(MessageFormat.format("{0} could not be deleted.", file)); 230 } 231 } 232 } 233 generatedFiles.clear(); 234 } 235 236 /** 237 * Return all the generated files and its types. 238 */ 239 public Iterable<File> getGeneratedFiles() { 240 return generatedFiles; 241 } 242 243 /** 244 * Delete all the generated source files made during the execution 245 * of this environment (those that have been registered with the 246 * "addGeneratedFile" method). 247 */ 248 public void deleteGeneratedFiles() { 249 synchronized (generatedFiles) { 250 for (File file : generatedFiles) { 251 if (file.getName().endsWith(".java")) { 252 boolean deleted = file.delete(); 253 if (verbose && !deleted) { 254 System.out.println(MessageFormat.format("{0} could not be deleted.", file)); 255 } 256 } 257 } 258 generatedFiles.clear(); 259 } 260 } 261 262 /** 263 * Parses arguments and fill fields of this object. 264 * 265 * @exception BadCommandLineException 266 * thrown when there's a problem in the command-line arguments 267 */ 268 public void parseArguments( String[] args ) throws BadCommandLineException { 269 270 for (int i = 0; i < args.length; i++) { 271 if(args[i].length()==0) 272 throw new BadCommandLineException(); 273 if (args[i].charAt(0) == '-') { 274 int j = parseArguments(args,i); 275 if(j==0) 276 throw new BadCommandLineException(WscompileMessages.WSCOMPILE_INVALID_OPTION(args[i])); 277 i += (j-1); 278 } else { 279 addFile(args[i]); 280 } 281 } 282 if(destDir == null) 283 destDir = new File("."); 284 if(sourceDir == null) 285 sourceDir = destDir; 286 } 287 288 289 /** 290 * Adds a file from the argume 291 * 292 * @param arg a file, could be a wsdl or xsd or a Class 293 */ 294 protected void addFile(String arg) throws BadCommandLineException {} 295 296 /** 297 * Parses an option {@code args[i]} and return 298 * the number of tokens consumed. 299 * 300 * @return 301 * 0 if the argument is not understood. Returning 0 302 * will let the caller report an error. 303 * @exception BadCommandLineException 304 * If the callee wants to provide a custom message for an error. 305 */ 306 protected int parseArguments(String[] args, int i) throws BadCommandLineException { 307 if (args[i].equals("-g")) { 308 debug = true; 309 return 1; 310 } else if (args[i].equals("-Xdebug")) { 311 debugMode = true; 312 return 1; 313 } else if (args[i].equals("-Xendorsed")) { 314 // this option is processed much earlier, so just ignore. 315 return 1; 316 } else if (args[i].equals("-verbose")) { 317 verbose = true; 318 return 1; 319 } else if (args[i].equals("-quiet")) { 320 quiet = true; 321 return 1; 322 } else if (args[i].equals("-keep")) { 323 keep = true; 324 return 1; 325 } else if (args[i].equals("-target")) { 326 String token = requireArgument("-target", args, ++i); 327 target = Target.parse(token); 328 if(target == null) 329 throw new BadCommandLineException(WscompileMessages.WSIMPORT_ILLEGAL_TARGET_VERSION(token)); 330 return 2; 331 } else if (args[i].equals("-classpath") || args[i].equals("-cp")) { 332 classpath = requireArgument("-classpath", args, ++i) + File.pathSeparator + System.getProperty("java.class.path"); 333 return 2; 334 } else if (args[i].equals("-d")) { 335 destDir = new File(requireArgument("-d", args, ++i)); 336 if (!destDir.exists()) 337 throw new BadCommandLineException(WscompileMessages.WSCOMPILE_NO_SUCH_DIRECTORY(destDir.getPath())); 338 return 2; 339 } else if (args[i].equals("-s")) { 340 sourceDir = new File(requireArgument("-s", args, ++i)); 341 keep = true; 342 if (!sourceDir.exists()) { 343 throw new BadCommandLineException(WscompileMessages.WSCOMPILE_NO_SUCH_DIRECTORY(sourceDir.getPath())); 344 } 345 return 2; 346 } else if (args[i].equals("-extension")) { 347 compatibilityMode = EXTENSION; 348 return 1; 349 } else if (args[i].startsWith("-help")) { 350 WeAreDone done = new WeAreDone(); 351 done.initOptions(this); 352 throw done; 353 } else if (args[i].equals("-Xnocompile")) { 354 // -nocompile implies -keep. this is undocumented switch. 355 nocompile = true; 356 keep = true; 357 return 1; 358 } else if (args[i].equals("-encoding")) { 359 encoding = requireArgument("-encoding", args, ++i); 360 try { 361 if (!Charset.isSupported(encoding)) { 362 throw new BadCommandLineException(WscompileMessages.WSCOMPILE_UNSUPPORTED_ENCODING(encoding)); 363 } 364 } catch (IllegalCharsetNameException icne) { 365 throw new BadCommandLineException(WscompileMessages.WSCOMPILE_UNSUPPORTED_ENCODING(encoding)); 366 } 367 return 2; 368 } else if (args[i].equals("-disableXmlSecurity")) { 369 disableXmlSecurity(); 370 return 1; 371 } else if (args[i].startsWith("-J")) { 372 if (javacOptions == null) { 373 javacOptions = new ArrayList<String>(); 374 } 375 javacOptions.add(args[i].substring(2)); 376 return 1; 377 } 378 return 0; 379 } 380 381 // protected method to allow overriding 382 protected void disableXmlSecurity() { 383 disableXmlSecurity= true; 384 } 385 386 /** 387 * Obtains an operand and reports an error if it's not there. 388 */ 389 public String requireArgument(String optionName, String[] args, int i) throws BadCommandLineException { 390 //if (i == args.length || args[i].startsWith("-")) { 391 if (args[i].startsWith("-")) { 392 throw new BadCommandLineException(WscompileMessages.WSCOMPILE_MISSING_OPTION_ARGUMENT(optionName)); 393 } 394 return args[i]; 395 } 396 397 List<String> getJavacOptions(List<String> existingOptions, WsimportListener listener) { 398 List<String> result = new ArrayList<String>(); 399 for (String o: javacOptions) { 400 if (o.contains("=") && !o.startsWith("A")) { 401 int i = o.indexOf('='); 402 String key = o.substring(0, i); 403 if (existingOptions.contains(key)) { 404 listener.message(WscompileMessages.WSCOMPILE_EXISTING_OPTION(key)); 405 } else { 406 result.add(key); 407 result.add(o.substring(i + 1)); 408 } 409 } else { 410 if (existingOptions.contains(o)) { 411 listener.message(WscompileMessages.WSCOMPILE_EXISTING_OPTION(o)); 412 } else { 413 result.add(o); 414 } 415 } 416 } 417 return result; 418 } 419 420 /** 421 * Used to signal that we've finished processing. 422 */ 423 public static final class WeAreDone extends BadCommandLineException {} 424 425 /** 426 * Get a URLClassLoader from using the classpath 427 */ 428 public ClassLoader getClassLoader() { 429 if (classLoader == null) { 430 classLoader = 431 new URLClassLoader(pathToURLs(classpath), 432 this.getClass().getClassLoader()); 433 } 434 return classLoader; 435 } 436 437 /** 438 * Utility method for converting a search path string to an array 439 * of directory and JAR file URLs. 440 * 441 * @param path the search path string 442 * @return the resulting array of directory and JAR file URLs 443 */ 444 public static URL[] pathToURLs(String path) { 445 StringTokenizer st = new StringTokenizer(path, File.pathSeparator); 446 URL[] urls = new URL[st.countTokens()]; 447 int count = 0; 448 while (st.hasMoreTokens()) { 449 URL url = fileToURL(new File(st.nextToken())); 450 if (url != null) { 451 urls[count++] = url; 452 } 453 } 454 if (urls.length != count) { 455 URL[] tmp = new URL[count]; 456 System.arraycopy(urls, 0, tmp, 0, count); 457 urls = tmp; 458 } 459 return urls; 460 } 461 462 /** 463 * Returns the directory or JAR file URL corresponding to the specified 464 * local file name. 465 * 466 * @param file the File object 467 * @return the resulting directory or JAR file URL, or null if unknown 468 */ 469 public static URL fileToURL(File file) { 470 String name; 471 try { 472 name = file.getCanonicalPath(); 473 } catch (IOException e) { 474 name = file.getAbsolutePath(); 475 } 476 name = name.replace(File.separatorChar, '/'); 477 if (!name.startsWith("/")) { 478 name = "/" + name; 479 } 480 481 // If the file does not exist, then assume that it's a directory 482 if (!file.isFile()) { 483 name = name + "/"; 484 } 485 try { 486 return new URL("file", "", name); 487 } catch (MalformedURLException e) { 488 throw new IllegalArgumentException("file"); 489 } 490 } 491 492 }