/* * Copyright (c) 2000 David Flanagan. All rights reserved. * This code is from the book Java Examples in a Nutshell, 2nd 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. * You may distribute it non-commercially as long as you retain this notice. * For a commercial use license, or to purchase the book (recommended), * visit http://www.davidflanagan.com/javaexamples2. */ package com.davidflanagan.examples.sql; 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 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 " + " "); } // 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 } } }