[ Team LiB ] Previous Section Next Section

18.4 Using the API Database

Example 18-4 displays a program, LookupAPI, that uses the database built by the MakeAPIDB program of Example 18-3 and makes interesting SQL queries against it. LookupAPI behaves as follows:

  • When invoked with the name of a class member, it lists the full name (including package and class) of each field and/or method that has that name.

  • When run with the name of a class, it lists the full name of every class in any package that has that name.

  • When called with a portion of a package name, it lists the names of all the packages that contain that string.

  • When invoked with the -l option and a class name, it lists every member of every class that has that name.

  • When run with the -l option and a portion of a package name, it lists all the classes and interfaces in any package that matches that string.

LookupAPI reads the same APIDB.props property file MakeAPIDB does. Or, alternatively, it reads a property file specified on the command line following a -p flag. Using the database connection parameters in the property file, the program connects to a database and executes the necessary SQL queries to return the desired information. Note that it calls the setReadOnly( ) method of the Connection object. Doing this provides a hint that the program performs only queries and doesn't modify the database in any way. For some database systems, this may improve efficiency. Other than the setReadOnly( ) method, this example doesn't introduce any new JDBC features. It simply serves as a real-world application of a database and demonstrates some of the powerful database queries that can be expressed using SQL.

Example 18-4. LookupAPI.java
package je3.sql;
import java.sql.*;
import java.io.FileInputStream;
import java.util.Properties;

/**
 * This program uses the database created by MakeAPIDB.  It opens a connection
 * to a database using the same property file used by MakeAPIDB.  Then it
 * queries that database in several interesting ways to obtain useful 
 * information about Java APIs.  It can be used to look up the fully-qualified
 * name of a member, class, or package, or it can be used to list the members
 * of a class or package.
 **/
public class LookupAPI {
    public static void main(String[  ] args) {
        Connection c = null;                // JDBC connection to the database
        try {
            // Some default values
            String target = null;             // The name to look up
            boolean list = false;             // List members or lookup name?
            String propfile = "APIDB.props";  // The file of db parameters
            
            // Parse the command-line arguments
            for(int i = 0; i < args.length; i++) {
                if (args[i].equals("-l")) list = true;
                else if (args[i].equals("-p")) propfile = args[++i];
                else if (target != null) 
                    throw new IllegalArgumentException("Unexpected argument: "
                                                       + args[i]);
                else target = args[i];
            }
            if (target == null)
                throw new IllegalArgumentException("No target specified");

            // 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 with the
            // -p argument.  This property file 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(propfile)); } // Try to load props
            catch (Exception e) {  }

            // 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 database driver
            Class.forName(driver);

            // And set up a connection to the specified database
            c = DriverManager.getConnection(database, user, password);

            // Tell it we will not do any updates.
            // This hint may improve efficiency.
            c.setReadOnly(true);

            // If the "-l" option was given, then list the members of
            // the named package or class.  Otherwise, lookup all
            // matches for the specified member, class, or package.
            if (list) list(c, target);
            else lookup(c, target);
        }
        // If anything goes wrong, print the exception and a usage message.  If
        // a SQLException is thrown, display the state message it includes.
        catch (Exception e) {
            System.out.println(e);
            if (e instanceof SQLException) 
                System.out.println(((SQLException) e).getSQLState( ));
            System.out.println("Usage: java LookupAPI [-l] [-p <propfile>] " +
                               "target");
        }
        // Always close the DB connection when we're done with it.
        finally {
            try { c.close( ); } catch (Exception e) {  }
        }
    }
    
    /**
     * This method looks up all matches for the specified target string in the
     * database.  First, it prints the full name of any members by that name.
     * Then it prints the full name of any classes by that name.  Then it 
     * prints the name of any packages that contain the specified name
     **/
    public static void lookup(Connection c, String target) throws SQLException
    {
        // Create the Statement object we'll use to query the database
        Statement s = c.createStatement( );
        
        // Go find all class members with the specified name
        s.executeQuery("SELECT DISTINCT " + 
                       "package.name, class.name, member.name, member.isField"+
                       " FROM package, class, member" + 
                       " WHERE member.name='" + target + "'" +
                       "   AND member.classId=class.id " +
                       "   AND class.packageId=package.id");
        
        // Loop through the results, and print them out (if there are any).
        ResultSet r = s.getResultSet( );
        while(r.next( )) {
            String pkg = r.getString(1);       // package name
            String cls = r.getString(2);       // class name
            String member = r.getString(3);    // member name
            boolean isField = r.getBoolean(4); // is the member a field?
            // Display this match
            System.out.println(pkg + "." + cls + "." + member + 
                               (isField?"":"( )"));
        }
        
        // Now look for a class with the specified name
        s.executeQuery("SELECT package.name, class.name " + 
                       "FROM package, class " + 
                       "WHERE class.name='" + target + "' " +
                       "  AND class.packageId=package.id");
        // Loop through the results and print them out
        r = s.getResultSet( );
        while(r.next( )) System.out.println(r.getString(1) + "." +
                                           r.getString(2));
        
        // Finally, look for a package that matches a part of the name.
        // Note the use of the SQL LIKE keyword and % wildcard characters
        s.executeQuery("SELECT name FROM package " + 
                       "WHERE name='" + target + "'" +
                       "   OR name LIKE '%." + target + ".%' " +
                       "   OR name LIKE '" + target + ".%' " +
                       "   OR name LIKE '%." + target + "'");
        // Loop through the results and print them out
        r = s.getResultSet( );
        while(r.next( )) System.out.println(r.getString(1));
        
        // Finally, close the Statement object
        s.close( );
    }
    
    /**
     * This method looks for classes with the specified name, or packages
     * that contain the specified name.  For each class it finds, it displays
     * all methods and fields of the class.  For each package it finds, it
     * displays all classes in the package.
     **/
    public static void list(Connection conn, String target) throws SQLException
    {
        // Create two Statement objects to query the database with
        Statement s = conn.createStatement( );
        Statement t = conn.createStatement( );
        
        // Look for a class with the given name
        s.executeQuery("SELECT package.name, class.name " + 
                       "FROM package, class " + 
                       "WHERE class.name='" + target + "' " +
                       "  AND class.packageId=package.id");
        // Loop through all matches
        ResultSet r = s.getResultSet( );
        while(r.next( )) {
            String p = r.getString(1);  // package name
            String c = r.getString(2);  // class name
            // Print out the matching class name
            System.out.println("class " + p + "." + c + " {");
            
            // Now query all members of the class
            t.executeQuery("SELECT DISTINCT member.name, member.isField " + 
                           "FROM package, class, member " + 
                           "WHERE package.name = '" + p + "' " +
                           "  AND class.name = '" + c + "' " + 
                           "  AND member.classId=class.id " +
                           "  AND class.packageId=package.id " +
                           "ORDER BY member.isField, member.name");
            
            // Loop through the ordered list of all members, and print them out
            ResultSet r2 = t.getResultSet( );
            while(r2.next( )) {
                String m = r2.getString(1);
                int isField = r2.getInt(2);
                System.out.println("  " + m + ((isField == 1)?"":"( )"));
            }
            // End the class listing
            System.out.println("}");
        }
        
        // Now go look for a package that matches the specified name
        s.executeQuery("SELECT name FROM package " +
                       "WHERE name='" + target + "'" +
                       "   OR name LIKE '%." + target + ".%' " +
                       "   OR name LIKE '" + target + ".%' " +
                       "   OR name LIKE '%." + target + "'");
        // Loop through any matching packages
        r = s.getResultSet( );
        while(r.next( )) {
            // Display the name of the package
            String p = r.getString(1);
            System.out.println("Package " + p + ": ");
            
            // Get a list of all classes and interfaces in the package
            t.executeQuery("SELECT class.name FROM package, class " + 
                           "WHERE package.name='" + p + "' " +
                           "  AND class.packageId=package.id " +
                           "ORDER BY class.name");
            // Loop through the list and print them out.
            ResultSet r2 = t.getResultSet( );
            while(r2.next( )) System.out.println("  " + r2.getString(1));
        }
        
        // Finally, close both Statement objects
        s.close( ); t.close( );
    }
}
    [ Team LiB ] Previous Section Next Section