View Javadoc
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 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      * strictly follow the compatibility rules specified in JAXWS spec
180      */
181     public static final int STRICT = 1;
182 
183     /**
184      * loosely follow the compatibility rules and allow the use of vendor
185      * binding extensions
186      */
187     public static final int EXTENSION = 2;
188 
189     /**
190      * this switch determines how carefully the compiler will follow
191      * the compatibility rules in the spec. Either <code>STRICT</code>
192      * or <code>EXTENSION</code>.
193      */
194     public int compatibilityMode = STRICT;
195 
196     public boolean isExtensionMode() {
197         return compatibilityMode == EXTENSION;
198     }
199 
200     public boolean debug = false;
201 
202     /**
203      * -Xdebug - gives complete stack trace
204      */
205     public boolean debugMode = false;
206 
207 
208     private final List<File> generatedFiles = new ArrayList<File>();
209     private ClassLoader classLoader;
210 
211 
212     /**
213      * Remember info on  generated source file generated so that it
214      * can be removed later, if appropriate.
215      */
216     public void addGeneratedFile(File file) {
217         generatedFiles.add(file);
218     }
219 
220     /**
221      * Remove generated files
222      */
223     public void removeGeneratedFiles(){
224         for(File file : generatedFiles){
225             if (file.getName().endsWith(".java")) {
226                 boolean deleted = file.delete();
227                 if (verbose && !deleted) {
228                     System.out.println(MessageFormat.format("{0} could not be deleted.", file));
229                 }
230             }
231         }
232         generatedFiles.clear();
233     }
234 
235     /**
236      * Return all the generated files and its types.
237      */
238     public Iterable<File> getGeneratedFiles() {
239         return generatedFiles;
240     }
241 
242     /**
243      * Delete all the generated source files made during the execution
244      * of this environment (those that have been registered with the
245      * "addGeneratedFile" method).
246      */
247     public void deleteGeneratedFiles() {
248         synchronized (generatedFiles) {
249             for (File file : generatedFiles) {
250                 if (file.getName().endsWith(".java")) {
251                     boolean deleted = file.delete();
252                     if (verbose && !deleted) {
253                         System.out.println(MessageFormat.format("{0} could not be deleted.", file));
254                     }
255                 }
256             }
257             generatedFiles.clear();
258         }
259     }
260 
261     /**
262      * Parses arguments and fill fields of this object.
263      *
264      * @exception BadCommandLineException
265      *      thrown when there's a problem in the command-line arguments
266      */
267     public void parseArguments( String[] args ) throws BadCommandLineException {
268 
269         for (int i = 0; i < args.length; i++) {
270             if(args[i].length()==0)
271                 throw new BadCommandLineException();
272             if (args[i].charAt(0) == '-') {
273                 int j = parseArguments(args,i);
274                 if(j==0)
275                     throw new BadCommandLineException(WscompileMessages.WSCOMPILE_INVALID_OPTION(args[i]));
276                 i += (j-1);
277             } else {
278                 addFile(args[i]);
279             }
280         }
281         if(destDir == null)
282             destDir = new File(".");
283         if(sourceDir == null)
284             sourceDir = destDir;
285     }
286 
287 
288     /**
289      * Adds a file from the argume
290      *
291      * @param arg a file, could be a wsdl or xsd or a Class
292      */
293     protected void addFile(String arg) throws BadCommandLineException {}
294 
295     /**
296      * Parses an option <code>args[i]</code> and return
297      * the number of tokens consumed.
298      *
299      * @return
300      *      0 if the argument is not understood. Returning 0
301      *      will let the caller report an error.
302      * @exception BadCommandLineException
303      *      If the callee wants to provide a custom message for an error.
304      */
305     protected int parseArguments(String[] args, int i) throws BadCommandLineException {
306         if (args[i].equals("-g")) {
307             debug = true;
308             return 1;
309         } else if (args[i].equals("-Xdebug")) {
310             debugMode = true;
311             return 1;
312         } else if (args[i].equals("-Xendorsed")) {
313             // this option is processed much earlier, so just ignore.
314             return 1;
315         } else if (args[i].equals("-verbose")) {
316             verbose = true;
317             return 1;
318         } else if (args[i].equals("-quiet")) {
319             quiet = true;
320             return 1;
321         } else if (args[i].equals("-keep")) {
322             keep = true;
323             return 1;
324         }  else if (args[i].equals("-target")) {
325             String token = requireArgument("-target", args, ++i);
326             target = Target.parse(token);
327             if(target == null)
328                 throw new BadCommandLineException(WscompileMessages.WSIMPORT_ILLEGAL_TARGET_VERSION(token));
329             return 2;
330         } else if (args[i].equals("-classpath") || args[i].equals("-cp")) {
331             classpath = requireArgument("-classpath", args, ++i) + File.pathSeparator + System.getProperty("java.class.path");
332             return 2;
333         } else if (args[i].equals("-d")) {
334             destDir = new File(requireArgument("-d", args, ++i));
335             if (!destDir.exists())
336                 throw new BadCommandLineException(WscompileMessages.WSCOMPILE_NO_SUCH_DIRECTORY(destDir.getPath()));
337             return 2;
338         } else if (args[i].equals("-s")) {
339             sourceDir = new File(requireArgument("-s", args, ++i));
340             keep = true;
341             if (!sourceDir.exists()) {
342                 throw new BadCommandLineException(WscompileMessages.WSCOMPILE_NO_SUCH_DIRECTORY(sourceDir.getPath()));
343             }
344             return 2;
345         } else if (args[i].equals("-extension")) {
346             compatibilityMode = EXTENSION;
347             return 1;
348         } else if (args[i].startsWith("-help")) {
349             WeAreDone done = new WeAreDone();
350             done.initOptions(this);
351             throw done;
352         } else if (args[i].equals("-Xnocompile")) {
353             // -nocompile implies -keep. this is undocumented switch.
354             nocompile = true;
355             keep = true;
356             return 1;
357         } else if (args[i].equals("-encoding")) {
358             encoding = requireArgument("-encoding", args, ++i);
359             try {
360                 if (!Charset.isSupported(encoding)) {
361                     throw new BadCommandLineException(WscompileMessages.WSCOMPILE_UNSUPPORTED_ENCODING(encoding));
362                 }
363             } catch (IllegalCharsetNameException icne) {
364                 throw new BadCommandLineException(WscompileMessages.WSCOMPILE_UNSUPPORTED_ENCODING(encoding));
365             }
366             return 2;
367         } else if (args[i].equals("-disableXmlSecurity")) {
368             disableXmlSecurity();
369             return 1;
370         } else if (args[i].startsWith("-J")) {
371             if (javacOptions == null) {
372                 javacOptions = new ArrayList<String>();
373             }
374             javacOptions.add(args[i].substring(2));
375             return 1;
376         }
377         return 0;
378     }
379 
380     // protected method to allow overriding
381     protected void disableXmlSecurity() {
382         disableXmlSecurity= true;
383     }
384 
385     /**
386      * Obtains an operand and reports an error if it's not there.
387      */
388     public String requireArgument(String optionName, String[] args, int i) throws BadCommandLineException {
389         //if (i == args.length || args[i].startsWith("-")) {
390         if (args[i].startsWith("-")) {
391             throw new BadCommandLineException(WscompileMessages.WSCOMPILE_MISSING_OPTION_ARGUMENT(optionName));
392         }
393         return args[i];
394     }
395 
396     List<String> getJavacOptions(List<String> existingOptions, WsimportListener listener) {
397         List<String> result = new ArrayList<String>();
398         for (String o: javacOptions) {
399             if (o.contains("=") && !o.startsWith("A")) {
400                 int i = o.indexOf('=');
401                 String key = o.substring(0, i);
402                 if (existingOptions.contains(key)) {
403                     listener.message(WscompileMessages.WSCOMPILE_EXISTING_OPTION(key));
404                 } else {
405                     result.add(key);
406                     result.add(o.substring(i + 1));
407                 }
408             } else {
409                 if (existingOptions.contains(o)) {
410                     listener.message(WscompileMessages.WSCOMPILE_EXISTING_OPTION(o));
411                 } else {
412                     result.add(o);
413                 }
414             }
415         }
416         return result;
417     }
418 
419     /**
420      * Used to signal that we've finished processing.
421      */
422     public static final class WeAreDone extends BadCommandLineException {}
423 
424     /**
425      * Get a URLClassLoader from using the classpath
426      */
427     public ClassLoader getClassLoader() {
428         if (classLoader == null) {
429             classLoader =
430                 new URLClassLoader(pathToURLs(classpath),
431                     this.getClass().getClassLoader());
432         }
433         return classLoader;
434     }
435 
436     /**
437      * Utility method for converting a search path string to an array
438      * of directory and JAR file URLs.
439      *
440      * @param path the search path string
441      * @return the resulting array of directory and JAR file URLs
442      */
443     public static URL[] pathToURLs(String path) {
444         StringTokenizer st = new StringTokenizer(path, File.pathSeparator);
445         URL[] urls = new URL[st.countTokens()];
446         int count = 0;
447         while (st.hasMoreTokens()) {
448             URL url = fileToURL(new File(st.nextToken()));
449             if (url != null) {
450                 urls[count++] = url;
451             }
452         }
453         if (urls.length != count) {
454             URL[] tmp = new URL[count];
455             System.arraycopy(urls, 0, tmp, 0, count);
456             urls = tmp;
457         }
458         return urls;
459     }
460 
461     /**
462      * Returns the directory or JAR file URL corresponding to the specified
463      * local file name.
464      *
465      * @param file the File object
466      * @return the resulting directory or JAR file URL, or null if unknown
467      */
468     public static URL fileToURL(File file) {
469         String name;
470         try {
471             name = file.getCanonicalPath();
472         } catch (IOException e) {
473             name = file.getAbsolutePath();
474         }
475         name = name.replace(File.separatorChar, '/');
476         if (!name.startsWith("/")) {
477             name = "/" + name;
478         }
479 
480         // If the file does not exist, then assume that it's a directory
481         if (!file.isFile()) {
482             name = name + "/";
483         }
484         try {
485             return new URL("file", "", name);
486         } catch (MalformedURLException e) {
487             throw new IllegalArgumentException("file");
488         }
489     }
490 
491 }