/* * @(#)JavaClassDepend.java 1.10 06/10/10 * * Copyright 1990-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 2 for more details (a copy is * included at /legal/license.txt). * * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions. * */ import java.io.FilenameFilter; import util.ClassFileFinder; import util.Set; import util.PathComponent; import java.util.Enumeration; import java.util.Dictionary; import java.util.Hashtable; import components.*; import util.ClassFile; import java.io.InputStream; import java.io.File; /* * Following is a simple driver program. * Here is an example of its use: * * java JavaClassDepend -classpath <your classes> -path java/lang/Object java/io/OptionalDataException * * And the example shows two dependence chains of equal length from java.lang.Object to * java.io.OptionalDataException: * * java/lang/Object => java/lang/Class => java/lang/ClassLoader => java/net/URL => java/io/ObjectInputStream => java/io/OptionalDataException * java/lang/Object => java/lang/Class => java/lang/ClassLoader => java/util/Hashtable => java/io/ObjectInputStream => java/io/OptionalDataException * example of class dependence analysis */ import util.*; import java.util.Enumeration; import dependenceAnalyzer.*; class JavaClassDepend { ClassFileFinder finder = new ClassFileFinder(); ClassnameFilter filter = new DummyFilter(); ClassDependenceAnalyzer cda = new ClassDependenceAnalyzer( finder, filter ); boolean forward; private void addToSearchPath( String pathname ){ finder.addToSearchPath( pathname ); } private void printNode( DependenceNode node, String classname ) { if ( node == null ){ System.out.println("Cannot find class "+classname); return; } cda.analyzeDependences( node ); if (forward) { printDependences( node ); } else { cda.analyzeAllDependences(); printReverseDependences( node ); } } private void showOne( String classname ){ DependenceNode node; int colon; int curbegin = 0; int pl = classname.length(); classname = classname.replace('.', '/'); char sepChar = File.pathSeparatorChar; while( (colon = classname.indexOf(sepChar,curbegin) ) != -1 ){ String thisclass = classname.substring( curbegin, colon ); node = cda.addNodeByName( thisclass ); printNode(node, thisclass); curbegin = colon+1; } if ( curbegin < pl ){ String thisclass = classname.substring( curbegin, pl ); node = cda.addNodeByName( thisclass ); printNode(node, thisclass); } } private void showAll(){ cda.analyzeAllDependences(); Enumeration e = cda.allNodes(); int nClasses = 0; while ( e.hasMoreElements()){ DependenceNode node = (DependenceNode)(e.nextElement()); if (forward) printDependences( node ); else printReverseDependences( node ); nClasses++; } System.out.println("TOTAL OF "+nClasses+" CLASSES"); } private void showPath( String srcclassname, String destclassname ){ ClassDependenceNode src = (ClassDependenceNode)cda.addNodeByName( srcclassname ); ClassDependenceNode dest = (ClassDependenceNode)cda.addNodeByName( destclassname ); Set tipset = new Set(); PathComponent r = new PathComponent( null, src ); tipset.addElement( r ); for ( int i = 0; i < 50; i++ ){ Set newtips = new Set(); Enumeration newGrowth = tipset.elements(); while ( newGrowth.hasMoreElements() ){ PathComponent t = (PathComponent)(newGrowth.nextElement() ); if ( t.link.state() == DependenceNode.UNANALYZED ) cda.analyzeDependences( t.link ); t.grow( newtips ); } if ( newtips.size() == 0 ){ /* exhaused the space without finding it. */ System.out.println("No path from "+srcclassname+" to "+destclassname ); return; } /* now see if we got to our destination. */ newGrowth = newtips.elements(); boolean foundDest = false; while ( newGrowth.hasMoreElements() ){ PathComponent t = (PathComponent)(newGrowth.nextElement() ); if ( t.link == dest ){ t.print( System.out ); System.out.println(); foundDest = true; } t.link.flags |= PathComponent.INSET; } if ( foundDest ){ return; } /* round and round. */ tipset = newtips; } System.out.println("Path from "+srcclassname+" to "+destclassname+" is too long" ); } private boolean checkArg(int index, int argLength, int nargNeed) { int r = argLength - index; if (r > nargNeed) return true; return false; } private void printUsage() { System.out.println("Usage: java JavaClassDepend [-options] <classname>"); System.out.println(" " ); System.out.println("where options include : "); System.out.println(" -help print out this message"); System.out.println(" -classpath <directories separated by colons>"); System.out.println(" list directories in which to look for classes"); System.out.println(" -showDirect <classname(s)> (if more than one class separated by colons)"); System.out.println(" show direct dependencies of this particular class"); System.out.println(" -showAll show all dependencies of the class in the graph"); System.out.println(" -path <classname1> <classname2>"); System.out.println(" show two dependence chains of equal length from <Class 1> to <Class 2>"); System.out.println(" -membersOf <classname>"); System.out.println(" show all member functions of a given class <classname>"); System.out.println(" -reverse put this option before -showDirect or -showAll to show the reverse graph of the reverse graph of specified <class> or all nodes"); System.out.println(" -loadClass <classname>"); System.out.println(" load Class <classname> into database"); } private void process( String args[] ){ boolean details = false; forward = true; for ( int i = 0; i < args.length; i++ ){ String a = args[i]; if ( a.equals("-classpath") ){ if (checkArg(i, args.length, 1)) addToSearchPath( args[++i] ); else printUsage(); continue; } if ( a.equals("-path") ){ if (checkArg(i, args.length, 2)) showPath( args[++i], args[++i] ); else printUsage(); continue; } if ( a.equals("-reverse")) { forward = false; continue; } if ( a.equals("-showDirect") ){ if (checkArg(i, args.length, 1)) showOne( args[++i] ); else printUsage(); continue; } if ( a.equals("-showAll") ){ details = true; continue; } if ( a.equals("-membersOf")) { if (checkArg(i, args.length, 1)) cda.printMembers(args[++i]); else printUsage(); continue; } if ( a.equals("-help")) { printUsage(); break; } if ( a.equals("-loadClass")) { if (checkArg(i, args.length, 1)) cda.addNodeByName(args[++i].replace('.', '/')); else printUsage(); continue; } printUsage(); } if (details) showAll(); } public static void main( String args[] ){ new JavaClassDepend().process( args ); } static void printDependences( DependenceNode node ){ if ( node.state() != DependenceNode.ANALYZED ){ if (node.state() == DependenceNode.ERROR) System.out.println( node.name()+" unanalysed"); return; } System.out.println( node.name()+" depends on:"); Enumeration e = node.dependsOn(); while ( e.hasMoreElements() ){ DependenceArc a = (DependenceArc)(e.nextElement()); System.out.println(" "+a.to().name() ); } } static void printReverseDependences( DependenceNode node ){ if ( node.state() != DependenceNode.ANALYZED ){ if (node.state() == DependenceNode.ERROR) System.out.println( node.name()+" unanalysed"); return; } System.out.println( node.name()+" depended on:"); Enumeration e = node.dependedOn(); while ( e.hasMoreElements() ){ DependenceArc a = (DependenceArc)(e.nextElement()); System.out.println(" "+a.from().name() ); } } } class DummyFilter extends util.ClassnameFilter{ public boolean accept( java.io.File dir, String className ){ return false; } }