472 * or if it's a public class if -apionly option is specified
473 */
474 private boolean matches(String classname, AccessFlags flags) {
475 if (options.apiOnly && !flags.is(AccessFlags.ACC_PUBLIC)) {
476 return false;
477 } else if (options.includePattern != null) {
478 return options.includePattern.matcher(classname.replace('/', '.')).matches();
479 } else {
480 return true;
481 }
482 }
483
484 private void findDependencies() throws IOException {
485 Dependency.Finder finder =
486 options.apiOnly ? Dependencies.getAPIFinder(AccessFlags.ACC_PROTECTED)
487 : Dependencies.getClassDependencyFinder();
488 Dependency.Filter filter = new DependencyFilter();
489
490 List<Archive> archives = new ArrayList<>();
491 Deque<String> roots = new LinkedList<>();
492 for (String s : classes) {
493 Path p = Paths.get(s);
494 if (Files.exists(p)) {
495 archives.add(Archive.getInstance(p));
496 } else {
497 if (isValidClassName(s)) {
498 roots.add(s);
499 } else {
500 warning("warn.invalid.arg", s);
501 }
502 }
503 }
504 sourceLocations.addAll(archives);
505
506 List<Archive> classpaths = new ArrayList<>(); // for class file lookup
507 classpaths.addAll(getClassPathArchives(options.classpath));
508 if (options.includePattern != null) {
509 archives.addAll(classpaths);
510 }
511 classpaths.addAll(PlatformClassPath.getArchives());
512
513 // add all classpath archives to the source locations for reporting
514 sourceLocations.addAll(classpaths);
515
516 // Work queue of names of classfiles to be searched.
517 // Entries will be unique, and for classes that do not yet have
518 // dependencies in the results map.
519 Deque<String> deque = new LinkedList<>();
520 Set<String> doneClasses = new HashSet<>();
521
522 // get the immediate dependencies of the input files
523 for (Archive a : archives) {
524 for (ClassFile cf : a.reader().getClassFiles()) {
525 String classFileName;
526 try {
527 classFileName = cf.getName();
528 } catch (ConstantPoolException e) {
529 throw new ClassFileError(e);
530 }
531
532 // tests if this class matches the -include or -apiOnly option if specified
533 if (!matches(classFileName, cf.access_flags)) {
534 continue;
535 }
536
537 if (!doneClasses.contains(classFileName)) {
538 doneClasses.add(classFileName);
539 }
540
541 for (Dependency d : finder.findDependencies(cf)) {
542 if (filter.accepts(d)) {
543 String cn = d.getTarget().getName();
544 if (!doneClasses.contains(cn) && !deque.contains(cn)) {
545 deque.add(cn);
546 }
547 a.addClass(d.getOrigin(), d.getTarget());
548 }
549 }
550 for (String name : a.reader().skippedEntries()) {
551 warning("warn.skipped.entry", name, a.getPathName());
552 }
553 }
554 }
555
556 // add Archive for looking up classes from the classpath
557 // for transitive dependency analysis
558 Deque<String> unresolved = roots;
559 int depth = options.depth > 0 ? options.depth : Integer.MAX_VALUE;
560 do {
561 String name;
562 while ((name = unresolved.poll()) != null) {
563 if (doneClasses.contains(name)) {
564 continue;
565 }
566 ClassFile cf = null;
567 for (Archive a : classpaths) {
575 }
576 if (!doneClasses.contains(classFileName)) {
577 // if name is a fully-qualified class name specified
578 // from command-line, this class might already be parsed
579 doneClasses.add(classFileName);
580 // process @jdk.Exported for JDK classes
581 if (isJDKArchive(a)) {
582 ((JDKArchive)a).processJdkExported(cf);
583 }
584 for (Dependency d : finder.findDependencies(cf)) {
585 if (depth == 0) {
586 // ignore the dependency
587 a.addClass(d.getOrigin());
588 break;
589 } else if (filter.accepts(d)) {
590 a.addClass(d.getOrigin(), d.getTarget());
591 String cn = d.getTarget().getName();
592 if (!doneClasses.contains(cn) && !deque.contains(cn)) {
593 deque.add(cn);
594 }
595 }
596 }
597 }
598 break;
599 }
600 }
601 if (cf == null) {
602 doneClasses.add(name);
603 }
604 }
605 unresolved = deque;
606 deque = new LinkedList<>();
607 } while (!unresolved.isEmpty() && depth-- > 0);
608 }
609
610 public void handleOptions(String[] args) throws BadArgs {
611 // process options
612 for (int i=0; i < args.length; i++) {
613 if (args[i].charAt(0) == '-') {
614 String name = args[i];
726 static {
727 Locale locale = Locale.getDefault();
728 try {
729 bundle = ResourceBundle.getBundle("com.sun.tools.jdeps.resources.jdeps", locale);
730 } catch (MissingResourceException e) {
731 throw new InternalError("Cannot find jdeps resource bundle for locale " + locale);
732 }
733 try {
734 versionRB = ResourceBundle.getBundle("com.sun.tools.jdeps.resources.version");
735 } catch (MissingResourceException e) {
736 throw new InternalError("version.resource.missing");
737 }
738 try {
739 jdkinternals = ResourceBundle.getBundle("com.sun.tools.jdeps.resources.jdkinternals");
740 } catch (MissingResourceException e) {
741 throw new InternalError("Cannot find jdkinternals resource bundle");
742 }
743 }
744 }
745
746 private List<Archive> getClassPathArchives(String paths) throws IOException {
747 List<Archive> result = new ArrayList<>();
748 if (paths.isEmpty()) {
749 return result;
750 }
751 for (String p : paths.split(File.pathSeparator)) {
752 if (p.length() > 0) {
753 List<Path> files = new ArrayList<>();
754 // wildcard to parse all JAR files e.g. -classpath dir/*
755 int i = p.lastIndexOf(".*");
756 if (i > 0) {
757 Path dir = Paths.get(p.substring(0, i));
758 try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, "*.jar")) {
759 for (Path entry : stream) {
760 files.add(entry);
761 }
762 }
763 } else {
764 files.add(Paths.get(p));
765 }
766 for (Path f : files) {
767 if (Files.exists(f)) {
768 result.add(Archive.getInstance(f));
769 }
770 }
771 }
772 }
773 return result;
774 }
775
776 class RawOutputFormatter implements Analyzer.Visitor {
777 private final PrintWriter writer;
778 private String pkg = "";
779 RawOutputFormatter(PrintWriter writer) {
780 this.writer = writer;
781 }
782 @Override
783 public void visitDependence(String origin, Archive originArchive,
784 String target, Archive targetArchive) {
785 String tag = toTag(target, targetArchive);
786 if (options.verbose == VERBOSE) {
787 writer.format(" %-50s -> %-50s %s%n", origin, target, tag);
788 } else {
789 if (!origin.equals(pkg)) {
790 pkg = origin;
791 writer.format(" %s (%s)%n", origin, originArchive.getName());
792 }
793 writer.format(" -> %-50s %s%n", target, tag);
|
472 * or if it's a public class if -apionly option is specified
473 */
474 private boolean matches(String classname, AccessFlags flags) {
475 if (options.apiOnly && !flags.is(AccessFlags.ACC_PUBLIC)) {
476 return false;
477 } else if (options.includePattern != null) {
478 return options.includePattern.matcher(classname.replace('/', '.')).matches();
479 } else {
480 return true;
481 }
482 }
483
484 private void findDependencies() throws IOException {
485 Dependency.Finder finder =
486 options.apiOnly ? Dependencies.getAPIFinder(AccessFlags.ACC_PROTECTED)
487 : Dependencies.getClassDependencyFinder();
488 Dependency.Filter filter = new DependencyFilter();
489
490 List<Archive> archives = new ArrayList<>();
491 Deque<String> roots = new LinkedList<>();
492 List<Path> paths = new ArrayList<>();
493 for (String s : classes) {
494 Path p = Paths.get(s);
495 if (Files.exists(p)) {
496 paths.add(p);
497 archives.add(Archive.getInstance(p));
498 } else {
499 if (isValidClassName(s)) {
500 roots.add(s);
501 } else {
502 warning("warn.invalid.arg", s);
503 }
504 }
505 }
506 sourceLocations.addAll(archives);
507
508 List<Archive> classpaths = new ArrayList<>(); // for class file lookup
509 classpaths.addAll(getClassPathArchives(options.classpath, paths));
510 if (options.includePattern != null) {
511 archives.addAll(classpaths);
512 }
513 classpaths.addAll(PlatformClassPath.getArchives());
514
515 // add all classpath archives to the source locations for reporting
516 sourceLocations.addAll(classpaths);
517
518 // Work queue of names of classfiles to be searched.
519 // Entries will be unique, and for classes that do not yet have
520 // dependencies in the results map.
521 Deque<String> deque = new LinkedList<>();
522 Set<String> doneClasses = new HashSet<>();
523
524 // get the immediate dependencies of the input files
525 for (Archive a : archives) {
526 for (ClassFile cf : a.reader().getClassFiles()) {
527 String classFileName;
528 try {
529 classFileName = cf.getName();
530 } catch (ConstantPoolException e) {
531 throw new ClassFileError(e);
532 }
533
534 // tests if this class matches the -include or -apiOnly option if specified
535 if (!matches(classFileName, cf.access_flags)) {
536 continue;
537 }
538
539 if (!doneClasses.contains(classFileName)) {
540 doneClasses.add(classFileName);
541 }
542
543 for (Dependency d : finder.findDependencies(cf)) {
544 if (filter.accepts(d)) {
545 String cn = d.getTarget().getName();
546 if (!doneClasses.contains(cn) && !deque.contains(cn)) {
547 deque.add(cn);
548 }
549 a.addClass(d.getOrigin(), d.getTarget());
550 } else {
551 // ensure that the parsed class is added the archive
552 a.addClass(d.getOrigin());
553 }
554 }
555 for (String name : a.reader().skippedEntries()) {
556 warning("warn.skipped.entry", name, a.getPathName());
557 }
558 }
559 }
560
561 // add Archive for looking up classes from the classpath
562 // for transitive dependency analysis
563 Deque<String> unresolved = roots;
564 int depth = options.depth > 0 ? options.depth : Integer.MAX_VALUE;
565 do {
566 String name;
567 while ((name = unresolved.poll()) != null) {
568 if (doneClasses.contains(name)) {
569 continue;
570 }
571 ClassFile cf = null;
572 for (Archive a : classpaths) {
580 }
581 if (!doneClasses.contains(classFileName)) {
582 // if name is a fully-qualified class name specified
583 // from command-line, this class might already be parsed
584 doneClasses.add(classFileName);
585 // process @jdk.Exported for JDK classes
586 if (isJDKArchive(a)) {
587 ((JDKArchive)a).processJdkExported(cf);
588 }
589 for (Dependency d : finder.findDependencies(cf)) {
590 if (depth == 0) {
591 // ignore the dependency
592 a.addClass(d.getOrigin());
593 break;
594 } else if (filter.accepts(d)) {
595 a.addClass(d.getOrigin(), d.getTarget());
596 String cn = d.getTarget().getName();
597 if (!doneClasses.contains(cn) && !deque.contains(cn)) {
598 deque.add(cn);
599 }
600 } else {
601 // ensure that the parsed class is added the archive
602 a.addClass(d.getOrigin());
603 }
604 }
605 }
606 break;
607 }
608 }
609 if (cf == null) {
610 doneClasses.add(name);
611 }
612 }
613 unresolved = deque;
614 deque = new LinkedList<>();
615 } while (!unresolved.isEmpty() && depth-- > 0);
616 }
617
618 public void handleOptions(String[] args) throws BadArgs {
619 // process options
620 for (int i=0; i < args.length; i++) {
621 if (args[i].charAt(0) == '-') {
622 String name = args[i];
734 static {
735 Locale locale = Locale.getDefault();
736 try {
737 bundle = ResourceBundle.getBundle("com.sun.tools.jdeps.resources.jdeps", locale);
738 } catch (MissingResourceException e) {
739 throw new InternalError("Cannot find jdeps resource bundle for locale " + locale);
740 }
741 try {
742 versionRB = ResourceBundle.getBundle("com.sun.tools.jdeps.resources.version");
743 } catch (MissingResourceException e) {
744 throw new InternalError("version.resource.missing");
745 }
746 try {
747 jdkinternals = ResourceBundle.getBundle("com.sun.tools.jdeps.resources.jdkinternals");
748 } catch (MissingResourceException e) {
749 throw new InternalError("Cannot find jdkinternals resource bundle");
750 }
751 }
752 }
753
754 /*
755 * Returns the list of Archive specified in cpaths and not included
756 * initialArchives
757 */
758 private List<Archive> getClassPathArchives(String cpaths, List<Path> initialArchives)
759 throws IOException
760 {
761 List<Archive> result = new ArrayList<>();
762 if (cpaths.isEmpty()) {
763 return result;
764 }
765
766 List<Path> paths = new ArrayList<>();
767 for (String p : cpaths.split(File.pathSeparator)) {
768 if (p.length() > 0) {
769 // wildcard to parse all JAR files e.g. -classpath dir/*
770 int i = p.lastIndexOf(".*");
771 if (i > 0) {
772 Path dir = Paths.get(p.substring(0, i));
773 try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, "*.jar")) {
774 for (Path entry : stream) {
775 paths.add(entry);
776 }
777 }
778 } else {
779 paths.add(Paths.get(p));
780 }
781 }
782 }
783 for (Path p : paths) {
784 if (Files.exists(p) && !hasSameFile(initialArchives, p)) {
785 result.add(Archive.getInstance(p));
786 }
787 }
788 return result;
789 }
790
791 private boolean hasSameFile(List<Path> paths, Path p2) throws IOException {
792 for (Path p1 : paths) {
793 if (Files.isSameFile(p1, p2)) {
794 return true;
795 }
796 }
797 return false;
798 }
799
800 class RawOutputFormatter implements Analyzer.Visitor {
801 private final PrintWriter writer;
802 private String pkg = "";
803 RawOutputFormatter(PrintWriter writer) {
804 this.writer = writer;
805 }
806 @Override
807 public void visitDependence(String origin, Archive originArchive,
808 String target, Archive targetArchive) {
809 String tag = toTag(target, targetArchive);
810 if (options.verbose == VERBOSE) {
811 writer.format(" %-50s -> %-50s %s%n", origin, target, tag);
812 } else {
813 if (!origin.equals(pkg)) {
814 pkg = origin;
815 writer.format(" %s (%s)%n", origin, originArchive.getName());
816 }
817 writer.format(" -> %-50s %s%n", target, tag);
|