Mega Code Archive

 
Categories / Java / File Input Output
 

A standalone program that reads a list of classes and builds a database of packages, classes, and class fields and metho

/*  * Copyright (c) 2004 David Flanagan.  All rights reserved.  * This code is from the book Java Examples in a Nutshell, 3nd Edition.  * It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied.  * You may study, use, and modify it for any non-commercial purpose,  * including teaching and use in open-source projects.  * You may distribute it non-commercially as long as you retain this notice.  * For a commercial use license, or to purchase the book,   * please visit http://www.davidflanagan.com/javaexamples3.  */ import java.io.BufferedReader; import java.io.FileInputStream; import java.io.FileReader; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.Properties; /**  * 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 classes to index from a file specified by args[0]       ArrayList classnames = new ArrayList();       BufferedReader in = new BufferedReader(new FileReader(args[0]));       String name;       while ((name = in.readLine()) != null)         classnames.add(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       String driver = p.getProperty("driver");       String database = p.getProperty("database");       String user = p.getProperty("user", "");       String password = p.getProperty("password", "");       // The driver and database properties are mandatory       if (driver == null)         throw new IllegalArgumentException("No driver specified!");       if (database == null)         throw new IllegalArgumentException("No database specified!");       // Load the driver. It registers itself with DriverManager.       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 name.       // The member table contains a class id, a member name, and an bit       // that indicates whether the class member is a field or a method.       Statement s = c.createStatement();       s.executeUpdate("CREATE TABLE package " + "(id INT, name VARCHAR(80))");       s.executeUpdate("CREATE TABLE class " + "(id INT, packageId INT, name VARCHAR(48))");       s.executeUpdate("CREATE TABLE member " + "(classId INT, name VARCHAR(48), isField BIT)");       // 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 use reflection       // to store them all in the tables       int numclasses = classnames.size();       for (int i = 0; i < numclasses; i++) {         try {           storeClass((String) classnames.get(i));         } catch (ClassNotFoundException e) {           System.out.println("WARNING: class not found: " + classnames.get(i) + "; SKIPPING");         }       }     } catch (Exception e) {       System.err.println(e);       if (e instanceof SQLException)         System.err.println("SQLState: " + ((SQLException) e).getSQLState());       System.err.println("Usage: java MakeAPIDB " + "<classlistfile> <propfile>");     }     // 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 Map package_to_id = new HashMap();   // 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       insertpackage.setInt(1, packageId); // Set statement args       insertpackage.setString(2, packagename);       insertpackage.executeUpdate(); // Insert into package 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 method name       insertmember.setBoolean(3, false); // It is not a field       insertmember.executeUpdate(); // Insert into db     }     // 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 field name       insertmember.setBoolean(3, true); // It is a field       insertmember.executeUpdate(); // Insert the record     }   } }