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