Java Examples In A Nutshell (3rd Edition) [Electronic resources]

O'Reilly Media, Inc

نسخه متنی -صفحه : 285/ 193
نمايش فراداده

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( );
}
}