langtools/src/share/classes/com/sun/tools/jdeps/JdepsTask.java
changeset 15030 2d8dec41f029
child 16290 b0b4f52de7ea
equal deleted inserted replaced
14965:bb1eb01b8c41 15030:2d8dec41f029
       
     1 /*
       
     2  * Copyright (c) 2012, 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 package com.sun.tools.jdeps;
       
    26 
       
    27 import com.sun.tools.classfile.ClassFile;
       
    28 import com.sun.tools.classfile.ConstantPoolException;
       
    29 import com.sun.tools.classfile.Dependencies;
       
    30 import com.sun.tools.classfile.Dependencies.ClassFileError;
       
    31 import com.sun.tools.classfile.Dependency;
       
    32 import com.sun.tools.classfile.Dependency.Location;
       
    33 import java.io.*;
       
    34 import java.text.MessageFormat;
       
    35 import java.util.*;
       
    36 import java.util.regex.Pattern;
       
    37 
       
    38 /**
       
    39  * Implementation for the jdeps tool for static class dependency analysis.
       
    40  */
       
    41 class JdepsTask {
       
    42     class BadArgs extends Exception {
       
    43         static final long serialVersionUID = 8765093759964640721L;
       
    44         BadArgs(String key, Object... args) {
       
    45             super(JdepsTask.this.getMessage(key, args));
       
    46             this.key = key;
       
    47             this.args = args;
       
    48         }
       
    49 
       
    50         BadArgs showUsage(boolean b) {
       
    51             showUsage = b;
       
    52             return this;
       
    53         }
       
    54         final String key;
       
    55         final Object[] args;
       
    56         boolean showUsage;
       
    57     }
       
    58 
       
    59     static abstract class Option {
       
    60         Option(boolean hasArg, String... aliases) {
       
    61             this.hasArg = hasArg;
       
    62             this.aliases = aliases;
       
    63         }
       
    64 
       
    65         boolean isHidden() {
       
    66             return false;
       
    67         }
       
    68 
       
    69         boolean matches(String opt) {
       
    70             for (String a : aliases) {
       
    71                 if (a.equals(opt)) {
       
    72                     return true;
       
    73                 } else if (opt.startsWith("--") && hasArg && opt.startsWith(a + "=")) {
       
    74                     return true;
       
    75                 }
       
    76             }
       
    77             return false;
       
    78         }
       
    79 
       
    80         boolean ignoreRest() {
       
    81             return false;
       
    82         }
       
    83 
       
    84         abstract void process(JdepsTask task, String opt, String arg) throws BadArgs;
       
    85         final boolean hasArg;
       
    86         final String[] aliases;
       
    87     }
       
    88 
       
    89     static abstract class HiddenOption extends Option {
       
    90         HiddenOption(boolean hasArg, String... aliases) {
       
    91             super(hasArg, aliases);
       
    92         }
       
    93 
       
    94         boolean isHidden() {
       
    95             return true;
       
    96         }
       
    97     }
       
    98 
       
    99     static Option[] recognizedOptions = {
       
   100         new Option(false, "-h", "-?", "--help") {
       
   101             void process(JdepsTask task, String opt, String arg) {
       
   102                 task.options.help = true;
       
   103             }
       
   104         },
       
   105         new Option(false, "-s", "--summary") {
       
   106             void process(JdepsTask task, String opt, String arg) {
       
   107                 task.options.showSummary = true;
       
   108                 task.options.verbose = Options.Verbose.SUMMARY;
       
   109             }
       
   110         },
       
   111         new Option(false, "-v", "--verbose") {
       
   112             void process(JdepsTask task, String opt, String arg) {
       
   113                 task.options.verbose = Options.Verbose.VERBOSE;
       
   114             }
       
   115         },
       
   116         new Option(true, "-V", "--verbose-level") {
       
   117             void process(JdepsTask task, String opt, String arg) throws BadArgs {
       
   118                 switch (arg) {
       
   119                     case "package":
       
   120                         task.options.verbose = Options.Verbose.PACKAGE;
       
   121                         break;
       
   122                     case "class":
       
   123                         task.options.verbose = Options.Verbose.CLASS;
       
   124                         break;
       
   125                     default:
       
   126                         throw task.new BadArgs("err.invalid.arg.for.option", opt);
       
   127                 }
       
   128             }
       
   129         },
       
   130         new Option(true, "-c", "--classpath") {
       
   131             void process(JdepsTask task, String opt, String arg) {
       
   132                 task.options.classpath = arg;
       
   133             }
       
   134         },
       
   135         new Option(true, "-p", "--package") {
       
   136             void process(JdepsTask task, String opt, String arg) {
       
   137                 task.options.packageNames.add(arg);
       
   138             }
       
   139         },
       
   140         new Option(true, "-e", "--regex") {
       
   141             void process(JdepsTask task, String opt, String arg) {
       
   142                 task.options.regex = arg;
       
   143             }
       
   144         },
       
   145         new Option(false, "-P", "--profile") {
       
   146             void process(JdepsTask task, String opt, String arg) {
       
   147                 task.options.showProfile = true;
       
   148             }
       
   149         },
       
   150         new Option(false, "-R", "--recursive") {
       
   151             void process(JdepsTask task, String opt, String arg) {
       
   152                 task.options.depth = 0;
       
   153             }
       
   154         },
       
   155         new HiddenOption(true, "-d", "--depth") {
       
   156             void process(JdepsTask task, String opt, String arg) throws BadArgs {
       
   157                 try {
       
   158                     task.options.depth = Integer.parseInt(arg);
       
   159                 } catch (NumberFormatException e) {
       
   160                     throw task.new BadArgs("err.invalid.arg.for.option", opt);
       
   161                 }
       
   162             }
       
   163         },
       
   164         new Option(false, "--version") {
       
   165             void process(JdepsTask task, String opt, String arg) {
       
   166                 task.options.version = true;
       
   167             }
       
   168         },
       
   169         new HiddenOption(false, "--fullversion") {
       
   170             void process(JdepsTask task, String opt, String arg) {
       
   171                 task.options.fullVersion = true;
       
   172             }
       
   173         },
       
   174 
       
   175     };
       
   176 
       
   177     private static final String PROGNAME = "jdeps";
       
   178     private final Options options = new Options();
       
   179     private final List<String> classes = new ArrayList<String>();
       
   180 
       
   181     private PrintWriter log;
       
   182     void setLog(PrintWriter out) {
       
   183         log = out;
       
   184     }
       
   185 
       
   186     /**
       
   187      * Result codes.
       
   188      */
       
   189     static final int EXIT_OK = 0, // Completed with no errors.
       
   190                      EXIT_ERROR = 1, // Completed but reported errors.
       
   191                      EXIT_CMDERR = 2, // Bad command-line arguments
       
   192                      EXIT_SYSERR = 3, // System error or resource exhaustion.
       
   193                      EXIT_ABNORMAL = 4;// terminated abnormally
       
   194 
       
   195     int run(String[] args) {
       
   196         if (log == null) {
       
   197             log = new PrintWriter(System.out);
       
   198         }
       
   199         try {
       
   200             handleOptions(args);
       
   201             if (options.help) {
       
   202                 showHelp();
       
   203             }
       
   204             if (options.version || options.fullVersion) {
       
   205                 showVersion(options.fullVersion);
       
   206             }
       
   207             if (classes.isEmpty() && !options.wildcard) {
       
   208                 if (options.help || options.version || options.fullVersion) {
       
   209                     return EXIT_OK;
       
   210                 } else {
       
   211                     showHelp();
       
   212                     return EXIT_CMDERR;
       
   213                 }
       
   214             }
       
   215             if (options.regex != null && options.packageNames.size() > 0) {
       
   216                 showHelp();
       
   217                 return EXIT_CMDERR;
       
   218             }
       
   219             if (options.showSummary && options.verbose != Options.Verbose.SUMMARY) {
       
   220                 showHelp();
       
   221                 return EXIT_CMDERR;
       
   222             }
       
   223             boolean ok = run();
       
   224             return ok ? EXIT_OK : EXIT_ERROR;
       
   225         } catch (BadArgs e) {
       
   226             reportError(e.key, e.args);
       
   227             if (e.showUsage) {
       
   228                 log.println(getMessage("main.usage.summary", PROGNAME));
       
   229             }
       
   230             return EXIT_CMDERR;
       
   231         } catch (IOException e) {
       
   232             return EXIT_ABNORMAL;
       
   233         } finally {
       
   234             log.flush();
       
   235         }
       
   236     }
       
   237 
       
   238     private final List<Archive> sourceLocations = new ArrayList<Archive>();
       
   239     private final Archive NOT_FOUND = new Archive(getMessage("artifact.not.found"));
       
   240     private boolean run() throws IOException {
       
   241         findDependencies();
       
   242         switch (options.verbose) {
       
   243             case VERBOSE:
       
   244             case CLASS:
       
   245                 printClassDeps(log);
       
   246                 break;
       
   247             case PACKAGE:
       
   248                 printPackageDeps(log);
       
   249                 break;
       
   250             case SUMMARY:
       
   251                 for (Archive origin : sourceLocations) {
       
   252                     for (Archive target : origin.getRequiredArchives()) {
       
   253                         log.format("%-30s -> %s%n", origin, target);
       
   254                     }
       
   255                 }
       
   256                 break;
       
   257             default:
       
   258                 throw new InternalError("Should not reach here");
       
   259         }
       
   260         return true;
       
   261     }
       
   262 
       
   263     private boolean isValidClassName(String name) {
       
   264         if (!Character.isJavaIdentifierStart(name.charAt(0))) {
       
   265             return false;
       
   266         }
       
   267         for (int i=1; i < name.length(); i++) {
       
   268             char c = name.charAt(i);
       
   269             if (c != '.'  && !Character.isJavaIdentifierPart(c)) {
       
   270                 return false;
       
   271             }
       
   272         }
       
   273         return true;
       
   274     }
       
   275 
       
   276     private void findDependencies() throws IOException {
       
   277         Dependency.Finder finder = Dependencies.getClassDependencyFinder();
       
   278         Dependency.Filter filter;
       
   279         if (options.regex != null) {
       
   280             filter = Dependencies.getRegexFilter(Pattern.compile(options.regex));
       
   281         } else if (options.packageNames.size() > 0) {
       
   282             filter = Dependencies.getPackageFilter(options.packageNames, false);
       
   283         } else {
       
   284             filter = new Dependency.Filter() {
       
   285                 public boolean accepts(Dependency dependency) {
       
   286                     return !dependency.getOrigin().equals(dependency.getTarget());
       
   287                 }
       
   288             };
       
   289         }
       
   290 
       
   291         List<Archive> archives = new ArrayList<Archive>();
       
   292         Deque<String> roots = new LinkedList<String>();
       
   293         for (String s : classes) {
       
   294             File f = new File(s);
       
   295             if (f.exists()) {
       
   296                 archives.add(new Archive(f, ClassFileReader.newInstance(f)));
       
   297             } else {
       
   298                 if (isValidClassName(s)) {
       
   299                     roots.add(s);
       
   300                 } else {
       
   301                     warning("warn.invalid.arg", s);
       
   302                 }
       
   303             }
       
   304         }
       
   305 
       
   306         List<Archive> classpaths = new ArrayList<Archive>(); // for class file lookup
       
   307         if (options.wildcard) {
       
   308             // include all archives from classpath to the initial list
       
   309             archives.addAll(getClassPathArchives(options.classpath));
       
   310         } else {
       
   311             classpaths.addAll(getClassPathArchives(options.classpath));
       
   312         }
       
   313         classpaths.addAll(PlatformClassPath.getArchives());
       
   314 
       
   315         // add all archives to the source locations for reporting
       
   316         sourceLocations.addAll(archives);
       
   317         sourceLocations.addAll(classpaths);
       
   318 
       
   319         // Work queue of names of classfiles to be searched.
       
   320         // Entries will be unique, and for classes that do not yet have
       
   321         // dependencies in the results map.
       
   322         Deque<String> deque = new LinkedList<String>();
       
   323         Set<String> doneClasses = new HashSet<String>();
       
   324 
       
   325         // get the immediate dependencies of the input files
       
   326         for (Archive a : archives) {
       
   327             for (ClassFile cf : a.reader().getClassFiles()) {
       
   328                 String classFileName;
       
   329                 try {
       
   330                     classFileName = cf.getName();
       
   331                 } catch (ConstantPoolException e) {
       
   332                     throw new ClassFileError(e);
       
   333                 }
       
   334                 a.addClass(classFileName);
       
   335                 if (!doneClasses.contains(classFileName)) {
       
   336                     doneClasses.add(classFileName);
       
   337                 }
       
   338                 for (Dependency d : finder.findDependencies(cf)) {
       
   339                     if (filter.accepts(d)) {
       
   340                         String cn = d.getTarget().getName();
       
   341                         if (!doneClasses.contains(cn) && !deque.contains(cn)) {
       
   342                             deque.add(cn);
       
   343                         }
       
   344                         a.addDependency(d);
       
   345                     }
       
   346                 }
       
   347             }
       
   348         }
       
   349 
       
   350         // add Archive for looking up classes from the classpath
       
   351         // for transitive dependency analysis
       
   352         Deque<String> unresolved = roots;
       
   353         int depth = options.depth > 0 ? options.depth : Integer.MAX_VALUE;
       
   354         do {
       
   355             String name;
       
   356             while ((name = unresolved.poll()) != null) {
       
   357                 if (doneClasses.contains(name)) {
       
   358                     continue;
       
   359                 }
       
   360                 ClassFile cf = null;
       
   361                 for (Archive a : classpaths) {
       
   362                     cf = a.reader().getClassFile(name);
       
   363                     if (cf != null) {
       
   364                         String classFileName;
       
   365                         try {
       
   366                             classFileName = cf.getName();
       
   367                         } catch (ConstantPoolException e) {
       
   368                             throw new ClassFileError(e);
       
   369                         }
       
   370                         a.addClass(classFileName);
       
   371                         if (!doneClasses.contains(classFileName)) {
       
   372                             // if name is a fully-qualified class name specified
       
   373                             // from command-line, this class might already be parsed
       
   374                             doneClasses.add(classFileName);
       
   375                             if (depth > 0) {
       
   376                                 for (Dependency d : finder.findDependencies(cf)) {
       
   377                                     if (filter.accepts(d)) {
       
   378                                         String cn = d.getTarget().getName();
       
   379                                         if (!doneClasses.contains(cn) && !deque.contains(cn)) {
       
   380                                             deque.add(cn);
       
   381                                         }
       
   382                                         a.addDependency(d);
       
   383                                     }
       
   384                                 }
       
   385                             }
       
   386                         }
       
   387                         break;
       
   388                     }
       
   389                 }
       
   390                 if (cf == null) {
       
   391                     NOT_FOUND.addClass(name);
       
   392                 }
       
   393             }
       
   394             unresolved = deque;
       
   395             deque = new LinkedList<String>();
       
   396         } while (!unresolved.isEmpty() && depth-- > 0);
       
   397     }
       
   398 
       
   399     private void printPackageDeps(PrintWriter out) {
       
   400         for (Archive source : sourceLocations) {
       
   401             SortedMap<Location, SortedSet<Location>> deps = source.getDependencies();
       
   402             if (deps.isEmpty())
       
   403                 continue;
       
   404 
       
   405             for (Archive target : source.getRequiredArchives()) {
       
   406                 out.format("%s -> %s%n", source, target);
       
   407             }
       
   408 
       
   409             Map<String, Archive> pkgs = new TreeMap<String, Archive>();
       
   410             SortedMap<String, Archive> targets = new TreeMap<String, Archive>();
       
   411             String pkg = "";
       
   412             for (Map.Entry<Location, SortedSet<Location>> e : deps.entrySet()) {
       
   413                 String cn = e.getKey().getClassName();
       
   414                 String p = packageOf(e.getKey());
       
   415                 Archive origin = Archive.find(e.getKey());
       
   416                 assert origin != null;
       
   417                 if (!pkgs.containsKey(p)) {
       
   418                     pkgs.put(p, origin);
       
   419                 } else if (pkgs.get(p) != origin) {
       
   420                     warning("warn.split.package", p, origin, pkgs.get(p));
       
   421                 }
       
   422 
       
   423                 if (!p.equals(pkg)) {
       
   424                     printTargets(out, targets);
       
   425                     pkg = p;
       
   426                     targets.clear();
       
   427                     out.format("   %s (%s)%n", p, origin.getFileName());
       
   428                 }
       
   429 
       
   430                 for (Location t : e.getValue()) {
       
   431                     p = packageOf(t);
       
   432                     Archive target = Archive.find(t);
       
   433                     if (!targets.containsKey(p)) {
       
   434                         targets.put(p, target);
       
   435                     }
       
   436                 }
       
   437             }
       
   438             printTargets(out, targets);
       
   439             out.println();
       
   440         }
       
   441     }
       
   442 
       
   443     private void printTargets(PrintWriter out, Map<String, Archive> targets) {
       
   444         for (Map.Entry<String, Archive> t : targets.entrySet()) {
       
   445             String pn = t.getKey();
       
   446             out.format("      -> %-40s %s%n", pn, getPackageInfo(pn, t.getValue()));
       
   447         }
       
   448     }
       
   449 
       
   450     private String getPackageInfo(String pn, Archive source) {
       
   451         if (PlatformClassPath.contains(source)) {
       
   452             String name = PlatformClassPath.getProfileName(pn);
       
   453             if (name.isEmpty()) {
       
   454                 return "JDK internal API (" + source.getFileName() + ")";
       
   455             }
       
   456             return options.showProfile ? name : "";
       
   457         }
       
   458         return source.getFileName();
       
   459     }
       
   460 
       
   461     private static String packageOf(Location loc) {
       
   462         String pkg = loc.getPackageName();
       
   463         return pkg.isEmpty() ? "<unnamed>" : pkg;
       
   464     }
       
   465 
       
   466     private void printClassDeps(PrintWriter out) {
       
   467         for (Archive source : sourceLocations) {
       
   468             SortedMap<Location, SortedSet<Location>> deps = source.getDependencies();
       
   469             if (deps.isEmpty())
       
   470                 continue;
       
   471 
       
   472             for (Archive target : source.getRequiredArchives()) {
       
   473                 out.format("%s -> %s%n", source, target);
       
   474             }
       
   475             out.format("%s%n", source);
       
   476             for (Map.Entry<Location, SortedSet<Location>> e : deps.entrySet()) {
       
   477                 String cn = e.getKey().getClassName();
       
   478                 Archive origin = Archive.find(e.getKey());
       
   479                 out.format("   %s (%s)%n", cn, origin.getFileName());
       
   480                 for (Location t : e.getValue()) {
       
   481                     cn = t.getClassName();
       
   482                     Archive target = Archive.find(t);
       
   483                     out.format("      -> %-60s %s%n", cn, getPackageInfo(t.getPackageName(), target));
       
   484                 }
       
   485             }
       
   486             out.println();
       
   487         }
       
   488     }
       
   489     public void handleOptions(String[] args) throws BadArgs {
       
   490         // process options
       
   491         for (int i=0; i < args.length; i++) {
       
   492             if (args[i].charAt(0) == '-') {
       
   493                 String name = args[i];
       
   494                 Option option = getOption(name);
       
   495                 String param = null;
       
   496                 if (option.hasArg) {
       
   497                     if (name.startsWith("--") && name.indexOf('=') > 0) {
       
   498                         param = name.substring(name.indexOf('=') + 1, name.length());
       
   499                     } else if (i + 1 < args.length) {
       
   500                         param = args[++i];
       
   501                     }
       
   502                     if (param == null || param.isEmpty() || param.charAt(0) == '-') {
       
   503                         throw new BadArgs("err.missing.arg", name).showUsage(true);
       
   504                     }
       
   505                 }
       
   506                 option.process(this, name, param);
       
   507                 if (option.ignoreRest()) {
       
   508                     i = args.length;
       
   509                 }
       
   510             } else {
       
   511                 // process rest of the input arguments
       
   512                 for (; i < args.length; i++) {
       
   513                     String name = args[i];
       
   514                     if (name.charAt(0) == '-') {
       
   515                         throw new BadArgs("err.option.after.class", name).showUsage(true);
       
   516                     }
       
   517                     if (name.equals("*") || name.equals("\"*\"")) {
       
   518                         options.wildcard = true;
       
   519                     } else {
       
   520                         classes.add(name);
       
   521                     }
       
   522                 }
       
   523             }
       
   524         }
       
   525     }
       
   526 
       
   527     private Option getOption(String name) throws BadArgs {
       
   528         for (Option o : recognizedOptions) {
       
   529             if (o.matches(name)) {
       
   530                 return o;
       
   531             }
       
   532         }
       
   533         throw new BadArgs("err.unknown.option", name).showUsage(true);
       
   534     }
       
   535 
       
   536     private void reportError(String key, Object... args) {
       
   537         log.println(getMessage("error.prefix") + " " + getMessage(key, args));
       
   538     }
       
   539 
       
   540     private void warning(String key, Object... args) {
       
   541         log.println(getMessage("warn.prefix") + " " + getMessage(key, args));
       
   542     }
       
   543 
       
   544     private void showHelp() {
       
   545         log.println(getMessage("main.usage", PROGNAME));
       
   546         for (Option o : recognizedOptions) {
       
   547             String name = o.aliases[0].substring(1); // there must always be at least one name
       
   548             name = name.charAt(0) == '-' ? name.substring(1) : name;
       
   549             if (o.isHidden() || name.equals("h")) {
       
   550                 continue;
       
   551             }
       
   552             log.println(getMessage("main.opt." + name));
       
   553         }
       
   554     }
       
   555 
       
   556     private void showVersion(boolean full) {
       
   557         log.println(version(full ? "full" : "release"));
       
   558     }
       
   559 
       
   560     private String version(String key) {
       
   561         // key=version:  mm.nn.oo[-milestone]
       
   562         // key=full:     mm.mm.oo[-milestone]-build
       
   563         if (ResourceBundleHelper.versionRB == null) {
       
   564             return System.getProperty("java.version");
       
   565         }
       
   566         try {
       
   567             return ResourceBundleHelper.versionRB.getString(key);
       
   568         } catch (MissingResourceException e) {
       
   569             return getMessage("version.unknown", System.getProperty("java.version"));
       
   570         }
       
   571     }
       
   572 
       
   573     public String getMessage(String key, Object... args) {
       
   574         try {
       
   575             return MessageFormat.format(ResourceBundleHelper.bundle.getString(key), args);
       
   576         } catch (MissingResourceException e) {
       
   577             throw new InternalError("Missing message: " + key);
       
   578         }
       
   579     }
       
   580 
       
   581     private static class Options {
       
   582         enum Verbose {
       
   583             CLASS,
       
   584             PACKAGE,
       
   585             SUMMARY,
       
   586             VERBOSE
       
   587         };
       
   588 
       
   589         boolean help;
       
   590         boolean version;
       
   591         boolean fullVersion;
       
   592         boolean showFlags;
       
   593         boolean showProfile;
       
   594         boolean showSummary;
       
   595         boolean wildcard;
       
   596         String regex;
       
   597         String classpath = "";
       
   598         int depth = 1;
       
   599         Verbose verbose = Verbose.PACKAGE;
       
   600         Set<String> packageNames = new HashSet<String>();
       
   601     }
       
   602 
       
   603     private static class ResourceBundleHelper {
       
   604         static final ResourceBundle versionRB;
       
   605         static final ResourceBundle bundle;
       
   606 
       
   607         static {
       
   608             Locale locale = Locale.getDefault();
       
   609             try {
       
   610                 bundle = ResourceBundle.getBundle("com.sun.tools.jdeps.resources.jdeps", locale);
       
   611             } catch (MissingResourceException e) {
       
   612                 throw new InternalError("Cannot find jdeps resource bundle for locale " + locale);
       
   613             }
       
   614             try {
       
   615                 versionRB = ResourceBundle.getBundle("com.sun.tools.jdeps.resources.version");
       
   616             } catch (MissingResourceException e) {
       
   617                 throw new InternalError("version.resource.missing");
       
   618             }
       
   619         }
       
   620     }
       
   621 
       
   622     private List<Archive> getArchives(List<String> filenames) throws IOException {
       
   623         List<Archive> result = new ArrayList<Archive>();
       
   624         for (String s : filenames) {
       
   625             File f = new File(s);
       
   626             if (f.exists()) {
       
   627                 result.add(new Archive(f, ClassFileReader.newInstance(f)));
       
   628             } else {
       
   629                 warning("warn.file.not.exist", s);
       
   630             }
       
   631         }
       
   632         return result;
       
   633     }
       
   634 
       
   635     private List<Archive> getClassPathArchives(String paths) throws IOException {
       
   636         List<Archive> result = new ArrayList<Archive>();
       
   637         if (paths.isEmpty()) {
       
   638             return result;
       
   639         }
       
   640         for (String p : paths.split(File.pathSeparator)) {
       
   641             if (p.length() > 0) {
       
   642                 File f = new File(p);
       
   643                 if (f.exists()) {
       
   644                     result.add(new Archive(f, ClassFileReader.newInstance(f)));
       
   645                 }
       
   646             }
       
   647         }
       
   648         return result;
       
   649     }
       
   650 }