// This example is from _Java Examples in a Nutshell_. (http://www.oreilly.com) // Copyright (c) 1997 by David Flanagan // This example is provided WITHOUT ANY WARRANTY either expressed or implied. // You may study, use, modify, and distribute it for non-commercial purposes. // For any commercial use, see http://www.davidflanagan.com/javaexamples import java.sql.*; import java.lang.reflect.*; import java.io.*; import java.util.*; /** * This class is a standalone program that reads a list of classes and * builds a database of packages, classes, and class fields and methods. **/ public class MakeAPIDB { public static void main(String args[]) { Connection c = null; // The connection to the database try { // Read the names of classes to index from a file specified by args[0] Vector classnames = new Vector(); BufferedReader in = new BufferedReader(new FileReader(args[0])); String name; while((name = in.readLine()) != null) classnames.addElement(name); // Now determine the values needed to set up the database connection // The program attempts to read a property file named "APIDB.props", // or optionally specified by args[1]. This property file (if any) // may contain "driver", "database", "user", and "password" properties // that specify the necessary values for connecting to the db. // If the properties file does not exist, or does not contain the named // properties, defaults will be used. Properties p = new Properties(); // Empty properties try { p.load(new FileInputStream(args[1])); } // Try to load properties catch (Exception e1) { try { p.load(new FileInputStream("APIDB.props")); } catch (Exception e2) {} } // Read values from Properties file, using the specified defaults if // they are not found. These defaults will probably not work for you! String driver = p.getProperty("driver", "postgres95.PGDriver"); String database = p.getProperty("database","jdbc:postgres95:///APIDB"); String user = p.getProperty("user", ""); String password = p.getProperty("password", ""); // Load the database driver Class.forName(driver); // And set up a connection to the specified database c = DriverManager.getConnection(database, user, password); // Create three new tables for our data // The package table contains a package id and a package name // The class table contains a class id, a package id, and a class name // The member table contains a class id, a member name, and an int // that indicates whether the class member is a field or a method. Statement s = c.createStatement(); s.executeUpdate("CREATE TABLE package " + "(id SMALLINT, name VARCHAR(80))"); s.executeUpdate("CREATE TABLE class " + "(id SMALLINT, packageId SMALLINT, name VARCHAR(48))"); s.executeUpdate("CREATE TABLE member " + "(classId SMALLINT,name VARCHAR(48),isField SMALLINT)"); // Prepare some statements that will be used to insert records into // these three tables. insertpackage = c.prepareStatement("INSERT INTO package VALUES(?,?)"); insertclass = c.prepareStatement("INSERT INTO class VALUES(?,?,?)"); insertmember = c.prepareStatement("INSERT INTO member VALUES(?,?,?)"); // Now loop through the list of classes and store them all in the tables for(int i = 0; i < classnames.size(); i++) storeClass((String)classnames.elementAt(i)); } catch (Exception e) { System.err.println(e); if (e instanceof SQLException) System.err.println("SQLState: " + ((SQLException)e).getSQLState()); System.err.println("Usage: java MakeAPIDB "); } // When we're done, close the connection to the database finally { try { c.close(); } catch (Exception e) {} } } /** * This hash table records the mapping between package names and package * id. This is the only one we need to store temporarily. The others are * stored in the db and don't have to be looked up by this program **/ static Hashtable package_to_id = new Hashtable(); // Counters for the package and class identifier columns static int packageId = 0, classId = 0; // Some prepared SQL statements for use in inserting // new values into the tables. Initialized in main() above. static PreparedStatement insertpackage, insertclass, insertmember; /** * Given a fully-qualified classname, this method stores the package name * in the package table (if it is not already there), stores the class name * in the class table, and then uses the Java Reflection API to look up all * methods and fields of the class, and stores those in the member table. **/ public static void storeClass(String name) throws SQLException, ClassNotFoundException { String packagename, classname; // Dynamically load the class. Class c = Class.forName(name); // Display output so the user knows that the program is progressing System.out.println("Storing data for: " + name); // Figure out the packagename and the classname int pos = name.lastIndexOf('.'); if (pos == -1) { packagename = ""; classname = name; } else { packagename = name.substring(0,pos); classname = name.substring(pos+1); } // Figure out what the package id is. If there is one, then this package // has already been stored in the database. Otherwise, assign an id, // and store it and the packagename in the db. Integer pid; pid = (Integer)package_to_id.get(packagename); // Check hashtable if (pid == null) { pid = new Integer(++packageId); // Assign an id package_to_id.put(packagename, pid); // Remember it in the hashtable insertpackage.setInt(1,packageId); // Set args to PreparedStatement insertpackage.setString(2,packagename); insertpackage.executeUpdate(); // Insert the package into db } // Now, store the classname in the class table of the database. // This record includes the package id, so that the class is linked to // the package that contains it. To store the class, we set arguments // to the PreparedStatement, then execute that statement insertclass.setInt(1, ++classId); // Set class identifier insertclass.setInt(2, pid.intValue()); // Set package identifier insertclass.setString(3, classname); // Set class name insertclass.executeUpdate(); // Insert the class record // Now, get a list of all non-private methods of the class, and // insert those into the "members" table of the database. Each // record includes the class id of the containing class, and also // a value that indicates that these are methods, not fields. Method[] methods = c.getDeclaredMethods(); // Get a list of methods for(int i = 0; i < methods.length; i++) { // For all non-private if (Modifier.isPrivate(methods[i].getModifiers())) continue; insertmember.setInt(1, classId); // Set the class id insertmember.setString(2, methods[i].getName()); // Set the method name insertmember.setInt(3, 0); // It is not a field insertmember.executeUpdate(); // Insert the record } // Do the same thing for the non-private fields of the class Field[] fields = c.getDeclaredFields(); // Get a list of fields for(int i = 0; i < fields.length; i++) { // For each non-private if (Modifier.isPrivate(fields[i].getModifiers())) continue; insertmember.setInt(1, classId); // Set the class id insertmember.setString(2, fields[i].getName()); // Set the field name insertmember.setInt(3, 1); // It is a field insertmember.executeUpdate(); // Insert the record } } }