3. Java as a programming language

Abstract:

API documentation is in http://java.sun.com/j2se/1.4.1/docs/api/

3.1. Programming - simple text manipulation program tonative.java

This simple program shows several features of Java programming.

Showing StringTokenizer, HashMap, argv array to main, Line Reader and PrintWriter using selected encoding. Showing exception declarations and handling

import java.io.*;
import java.util.*;

public class tonative {

static		boolean dotabs = false;
static		boolean undotabs = false;
static		int tabsize = 4;

static HashMap replace_map = null;

private static void readReplaceMap( String file_in )
{
	try {
	InputStream is;
	if ( file_in == null )
		is = System.in;
	else
		is = new FileInputStream( file_in );
	BufferedReader br = new BufferedReader( new InputStreamReader( is, "UTF-8" ) );

	while ( true )
	{
		String line = br.readLine();
		if ( line == null )
			break;
		StringTokenizer stk = new StringTokenizer( line );
		if ( stk.countTokens() == 2 )
		{
			String s1 = stk.nextToken();
			String s2 = stk.nextToken();
			if ( replace_map == null ) replace_map = new HashMap(30);
			replace_map.put( s1, s2 );
			debugmsg("replace_map: " + s1 + " " + s2 );
		}
	}

	}
	catch ( IOException iox )
	{
	}

}

public static void
debugmsg( String s )
{
//    System.err.println( s );
}

public
static void main(String arg[])
{
	String file_in = null;
	String file_out = null;
	boolean multifile = false;
	int i;
	for( i=0; i<arg.length; i++ )
	{
		if ( multifile )
		{
			doFiles( arg[i], "uu" );
			File f = new File("uu");
			f.renameTo( new File(arg[i]) );
			f = null;
		}

		if ( arg[i].equals("-replace_map") )
		{
			readReplaceMap( arg[++i] );
		}

		if ( arg[i].equals("-multiple") )
			multifile = true;
		if ( arg[i].equals("-in") )
			file_in = arg[i+1];
		if ( arg[i].equals("-out") )
			file_out = arg[i+1];
		if ( arg[i].equals("-notabs") )
		{
			undotabs = true;
			dotabs = false;
		}
		if ( arg[i].equals("-tabs") )
		{
			dotabs = true;
			undotabs = false;
		}
		if ( arg[i].equals("-?") || arg[i].equals("-help") )
		{
			printUsage();
			System.exit(0);
		}
	}

	if ( multifile )
		return;

	doFiles( file_in, file_out );

}

public static void
doFiles( String file_in, String file_out )
{
	System.err.println("IN " + file_in + " OUT " + file_out );
	InputStream is;
	OutputStream os;
	boolean autoflush = false;

	try {
		if ( file_in == null )
			is = System.in;
		else
			is = new FileInputStream( file_in );

		if ( file_out == null )
		{
			os = System.out;
			autoflush = true;
		}
		else
			os = new FileOutputStream( file_out );

		debugmsg("IN " + is.toString() + " OUT " + os.toString() );
		LineNumberReader lin_rd;
		PrintWriter lin_wr;
		lin_rd = new LineNumberReader( new InputStreamReader( is, "UTF-8" ) );
		lin_wr = new PrintWriter(  new OutputStreamWriter(os, "UTF-8"), autoflush );
		while( true )
		{
			String line = lin_rd.readLine();
			debugmsg("line: " + line);
			if ( line != null )
			{
				if ( replace_map != null )
				{
					Iterator it = replace_map.keySet().iterator();
					while ( it.hasNext() )
					{
						String k = (String)it.next();
						line = line.replaceAll( k, (String)replace_map.get(k) );
					}
				}

				if ( dotabs )
					line = inserttabs( line, tabsize );
				if ( undotabs )
					line = removetabs( line, tabsize );
				lin_wr.println( trim_trailing_whitespace( line ) );
			}
			else
				break;
		}
		lin_wr.close();
		lin_rd.close();
	}
	catch( IOException ioex )
	{
		System.err.println("Exception " + ioex.toString() );
	}
}


public static void
printUsage()
{
	StringBuffer sb = new StringBuffer("");
	sb.append("\n");
	sb.append("java tonative [-in filename] [-out filename] [-tabs|-notabs] [-multiple files...]");
	sb.append("\n");
	sb.append("Note: the tabs are 4 spaces - they will only be used to fill/unfill the leading whitespace\n");
	sb.append("\n");
	sb.append("The default in/out streams are stdin/stdout");
	sb.append("\n");
	sb.append("The presence of -multiple invalidates -in/-out arguments: following files are converted in place");
	sb.append("\n");

	System.err.println( sb.toString() );
}

public static
String
removetabs( String line, int tabsize )
{
	int LW=0;
	int rest = end_of_whitespace(line);
	StringBuffer sb = new StringBuffer("");
	LW = length_of_whitespace( line, tabsize );
	debugmsg( " LW " + LW  + " rest " + rest);

	int i;
	for( i=0; i<LW; i++ ) sb.append( ' ' );

	sb.append( line.substring(rest) );
	return sb.toString();
}

public static
String
inserttabs( String line, int tabsize )
{
	int LW=0;
	int rest = end_of_whitespace(line);
	StringBuffer sb = new StringBuffer("");
	LW = length_of_whitespace( line, tabsize );
	debugmsg( " LW " + LW  + " rest " + rest);

	int i;
	for( i=0; i+tabsize<=LW; i+=tabsize ) sb.append( '\t' );
	for( ; i<LW; i++ ) sb.append( ' ' );

	sb.append( line.substring(rest) );
	return sb.toString();
}

public static
String
trim_trailing_whitespace( String line )
{
	int i;
	int rest = end_of_whitespace(line);
	StringBuffer sb = new StringBuffer("");
	sb.append( line.substring(0,rest) );
	sb.append( line.substring(rest).trim() );
	return sb.toString();
}

public static
int
end_of_whitespace( String line )
{
	int i;
	for(i=0; i<line.length(); i++ )
	{
		char c = line.charAt(i);
		if (c == ' ' || c == '\t')
			continue;
		break;
	}
	return i;
}

public static
int
length_of_whitespace( String line, int tabsize )
{
	int i;
	int L = 0;
	for(i=0; i<line.length(); i++ )
	{
		char c = line.charAt(i);
		if (c == ' ' )
			L++;
		else if (c == '\t' )
		{
			L += ( tabsize - (L%tabsize) );
		}
		else
		{
			break;
		}
	}
	return L;
}

}

3.2. Complex XML Editor - DomDoc.java

Let us look at a more complex program using javax and other extension libraries. But first examine the basic abstraction pattern. It is depicts the division of knowledge between three items. The abstraction answers the question - what, the implementation - the question how, and lastly the client or caller the question - when. The pervasive usage of this pattern in Java programming is very instructive to programmers and helps them to quickly embrace and stick to the right methodologies.

Also showing package declaration, imports of abstractions and implementations. Show some simple methods for reading, writing and transforming XML.

package tjg.xml;

import java.io.*;
import java.text.*;
import java.net.URL;
import java.net.MalformedURLException;

/*
this is needed for the transform
*/
import javax.xml.transform.*;
import javax.xml.transform.stream.*;
import javax.xml.transform.dom.*;

import org.w3c.dom.*;
import org.xml.sax.InputSource;
import org.xml.sax.SAXParseException;
import org.xml.sax.SAXException;
import org.xml.sax.EntityResolver;

import java.util.*;

import tjg.Debug;
import tjg.ui.CommandProcessor;
import tjg.ui.CommandUI;

/**
encapsulates a DOM document parsed from a XML file
has a number of static variables defining the parsing environment
*/
public class DomDoc extends DomCommandProcessor {

protected Document main_doc = null;
public static String dir = ".";
public static final String ID_MAP_NAME = "ID_map";

private Hashtable type_catalog = null;
private Hashtable catalog = null;
private HashMap m_id_map = null;

public static String g_id_name = "ID";
public static EntityResolver g_resolver = null;
public static String dtddirs = ".";

public static boolean g_namespaceaware = false;
public static boolean g_validating = false;
public static boolean g_schemavalidating = false;
public static String g_parsername = "xerces";

/**
externally setup parser environment
@param
	parsertype - default xerces
@param
	namespaceaware - default false
@param
	validating - default false
@param
	schemavalidating- default false (caution this only works with xerces now and when validating is true)
*/
public static void setupParser(
	String parsertype,
	boolean namespaceaware,
	boolean validating,
	boolean schemavalidating)
{
	g_parsername = parsertype;
	g_namespaceaware = namespaceaware;
	g_validating = validating;
	g_schemavalidating = schemavalidating;
}

public static void main(String args[] )
{
	boolean swing_guicmd = true;
	boolean guicmd = false;
	boolean transform = false;
	String xsl = null;
	String output = null;
	String ifilename = null;
	String ofilename = null;
	int dbglevel = 0;
	int i = 0;
	Debug.setprintlevel( 0 );
	Document md = null;
	try {
	for (i=0; i<args.length; i++)
	{
		if ( args[i].equals("-ifile") )
		{
			ifilename = args[i+1]; i++;
		}
		if ( args[i].equals("-ofile") )
		{
			ofilename = args[i+1]; i++;
		}
		if ( args[i].equals("-id_name") )
		{
			g_id_name = args[i+1]; i++;
		}
		if ( args[i].equals("-dtds") )
		{
			dtddirs = args[i+1]; i++;
		}
		if ( args[i].equals("-debug") )
		{
			dbglevel = 1;
		}
		if ( args[i].equals("-transform") )
		{
			transform = true;
		}
		if ( args[i].equals("-xsl") )
		{
			xsl = args[i+1]; i++;
		}
		if ( args[i].equals("-output") )
		{
			output = args[i+1]; i++;
		}
		if ( args[i].equals("-noswingui") )
		{
			swing_guicmd = false;
		}
		if ( args[i].equals("-parser") )
		{
			g_parsername = args[i+1]; i++;
		}
		if ( args[i].equals("-namespaces") )
		{
			g_namespaceaware = true;
		}
		if ( args[i].equals("-validating") )
		{
			g_validating = true;
		}
		if ( args[i].equals("-schemavalidating") )
		{
			g_schemavalidating = true;
		}
		if ( args[i].equals("-nocui") )
		{
			guicmd = false;
		}
		if ( args[i].equals("-nogui") )
		{
			guicmd = false;
			swing_guicmd = false;
		}
	}
	}
	catch (Exception e) {
		Debug.print("Exception" + e);
		System.exit(-1);
	}

	if ( ifilename == null )
		ifilename = "";

	Debug.setprintlevel( dbglevel );
	if ( dbglevel != 0 )
		tjg.Util.printProperties();
	makeResolver( dtddirs );

	try {

	DomDoc x = new DomDoc(g_id_name);

	x.load(ifilename);

	md = x.getDocument();
	if ( md == null )
	{
		Debug.print("No document");
	}

	if ( transform )
	{
		Debug.print("Transform Output file: " + output );
		try {
		x.processByXSL( new BufferedOutputStream( new FileOutputStream(output)), xsl );
		}
		catch ( IOException miox )
		{
			Debug.print("IOException: " + miox.getMessage() );
		}
		System.exit(0);
	}

	if ( md != null )
	{

		DocumentType dt = md.getDoctype();
		if ( dt != null )
		{
			Debug.print("DTD: " + dt.getName() );
			Debug.print("DTD PublicId: " + dt.getPublicId() );
			Debug.print("DTD: SystemId: " + dt.getSystemId() );
		}

		if ( guicmd )
		{
			x.setupCommandProcessor( md );
			CommandUI cui = new CommandUI( x );
			cui.setTitle( new String("DomDoc-> " + ifilename) );
			cui.run();
			CommandUI.waitForClose( cui );
			cui = null;
		}
	}

	if ( swing_guicmd )
	{
		Debug.print("runSwingUI");
		runSwingUI(x, ifilename, ofilename);
	}

	if ( !swing_guicmd && !guicmd )
	{
		try {
			if ( ofilename != null )
			{
				Debug.print( "output to file: " + ofilename );
				FileOutputStream fo = new FileOutputStream( ofilename );
				x.writeDocumentbyTrans( new BufferedOutputStream( fo ) );
				fo.close();
			}
		}
		catch( IOException iox )
		{
			Debug.print( "IOException: " + iox );
		}
	}

	}
	catch ( Throwable thr )
	{
		System.err.println( "What happened?: " + thr );
	}
	System.exit(0);
}

/**
call it to establish a resolver path
@param s - directories separated by spaces
*/
public static void makeResolver(String s)
{
	g_resolver = new DResolver( s );
	dtddirs = s;
}

private static void runSwingUI(DomDoc x, String ifile, String ofile)
{
	TreeView tv = new TreeView( x, ifile, ofile, x.m_id_name );
	tv.setTitle( "XML View-Edit: input [" + ifile + "] --> output [" + ofile + "]" );
	tv.run();
}

public void processByXSL(OutputStream out, String xsl) throws IOException
{
	if ( main_doc == null )
	{
		Debug.print("No main doc");
		return;
	}
	if ( xsl == null )
		return;
	DOMSource dms = new DOMSource( main_doc.getDocumentElement() );
	OutputStreamWriter cw = new OutputStreamWriter(out, "UTF-8");
	javax.xml.transform.stream.StreamResult srr = new javax.xml.transform.stream.StreamResult( cw );
	try {
		TransformerFactory tf = TransformerFactory.newInstance();
		Transformer t = tf.newTransformer( new StreamSource( xsl ) );
		t.setOutputProperty( javax.xml.transform.OutputKeys.INDENT, "yes" );
		t.transform( dms, srr );
		Debug.print( "processByXSL OK" );
	}
	catch( Exception exx )
	{
		Debug.print( "processByXSL exception: " + exx.getMessage()  );
	}
}

public void writeDocumentbyTrans(OutputStream os) throws IOException
{
	if ( main_doc == null )
	{
		Debug.print("No main doc");
		return;
	}

	OutputStreamWriter cw = new OutputStreamWriter(os, "UTF-8");
	DOMSource dms = new DOMSource( main_doc.getDocumentElement() );
	javax.xml.transform.stream.StreamResult srr = new javax.xml.transform.stream.StreamResult( cw );

	TransformerFactory trf = null;
	Transformer tr = null;
	DocumentType dt = main_doc.getDoctype();
	try {
		Debug.print("Writing by transformer");
		trf = TransformerFactory.newInstance();
		tr = trf.newTransformer( );
		tr.setOutputProperty( javax.xml.transform.OutputKeys.METHOD, "xml" );
		tr.setOutputProperty( javax.xml.transform.OutputKeys.INDENT, "yes" );
		tr.setOutputProperty( javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION, "no" );
		tr.setOutputProperty( javax.xml.transform.OutputKeys.STANDALONE, "yes" );
		if ( dt != null )
		{
			if ( dt.getSystemId() != null )
			tr.setOutputProperty( javax.xml.transform.OutputKeys.DOCTYPE_SYSTEM, dt.getSystemId() );
		}
		tr.transform( dms, srr );
	}
	catch ( Exception whate )
	{
		System.err.println( "Exc: " + whate );
	}
}



/**
loads and parses a XML document from file
*/
public boolean load( String ifilename )
{
	InputStream is = null;
	try {
		is = new BufferedInputStream( new FileInputStream( ifilename ) );
	}
	catch ( IOException iox )
	{
		Debug.print("Error opening " + ifilename );
		return false;
	}
	Document md = null;
	if ( is != null )
		md = getDocument(is, ifilename);
	if ( md != null )
	{
		makeCatalogs();
		initIDMap();
		doc_for_command_processor = md;
		return true;
	}
	return false;
}


/**
loads and parses a XML document from input stream
*/
protected Document getDocument( InputStream is, String baseuri )
{

	if ( is == null )
	{
		Debug.print( "InputStream null");
		return null;
	}

	Document md = null;

	API ap = new API();

	md = ap.parse( g_parsername, is, baseuri, g_namespaceaware, g_validating, g_schemavalidating, g_resolver);

	Debug.print( "Errors: " + ap.getNumberOfErrors() + "\n" + ap.getErrorReport() );

	if ( md == null )
		return null;

	main_doc = md;
	catalog = new Hashtable( 51 );
	type_catalog = new Hashtable( 13 );

	return md;
}
....
}

3.3. Database access using JDBC - SQLTool.java

Showing handling of database connection, discussing programming to an abstract JDBC interface. Implementation is provided from "behind" by driver manager.

package tjg.sql;

import java.sql.*;
import tjg.ui.CommandUI;
import tjg.ui.CommandProcessor;
import tjg.Debug;
import java.util.*;
import java.io.*;

public class SQLtool implements CommandProcessor {

private boolean isConnected = false;
private Connection dbconnection;
private DatabaseMetaData dbmeta;
private Vector m_tablenames;
private Properties m_properties; // connection properties
private String lastMessage = "no message";

public SQLtool( String user, String password, String dbname, String hostname, String port )
{
	m_tablenames = new Vector();
	dbmeta = null;
	m_properties = new Properties();
	if ( user != null )
		m_properties.setProperty("user", user);
	if ( password != null )
	m_properties.setProperty("password", password);
	if ( dbname != null )
	m_properties.setProperty("dbname", dbname);
	if ( hostname != null )
	m_properties.setProperty("hostname", hostname);
	if ( port != null )
	m_properties.setProperty("port", port);

}

public SQLtool( String props )
{
	m_tablenames = new Vector();
	dbmeta = null;
	loadConnectionInfo( props );
}

private boolean openConnection()
{
	Connection c = null;
	String connectString;
	StringBuffer sb = new StringBuffer("jdbc:postgresql:");
	sb.append("//" + m_properties.getProperty("hostname"));
	sb.append(":" + m_properties.getProperty("port"));
	sb.append("/" + m_properties.getProperty("dbname") );
	connectString = sb.toString();
	Debug.print( connectString );
	try {
	c = DriverManager.getConnection(connectString, 
		m_properties.getProperty("user"),
		m_properties.getProperty("password")
		 );
	if ( c != null )
	{
		dbmeta = c.getMetaData();
		refreshMetaInfo();
	}
	}
	catch( SQLException sex )
	{
		lastMessage = sex.getMessage();
		Debug.print("openConnection: Exception: " + lastMessage );
		c = null;
	}

	isConnected = ( c != null );
	dbconnection = c;
	return isConnected;
}

private boolean loadConnectionInfo( String fname )
{
	Properties prop = new Properties();
	try {
		prop.load( new FileInputStream( fname ) );
	}
	catch( IOException iox )
	{
		prop = null;
		lastMessage = iox.getMessage();
	}

	if ( prop != null )
		m_properties = prop;
	return ( prop != null);
}

private void refreshMetaInfo()
{
	if ( dbmeta == null )
		return;
	ResultSet rs = null;
	Vector v = new Vector();
	try {
		rs = dbmeta.getTables(null, null, null, null );
		int i;
		while( rs.next() )
		{
			v.addElement(new String(rs.getString(3)) );
		}
		m_tablenames = v;
	}
	catch( SQLException sex )
	{
		lastMessage = sex.getMessage();
		Debug.print("Exception " + sex.getMessage() );
	}
}

private void closeConnection()
{
	Connection c = dbconnection;
	isConnected = false;
	dbconnection = null;
	if ( c == null )
		return;
	try {
	c.close();
	}
	catch( SQLException csex )
	{
		lastMessage = csex.getMessage();
		Debug.print("Exception on close " + csex.getMessage() );
	}
}

public void run()
{
	CommandUI cui = new CommandUI( this );
	cui.setSize(600, 300 );
	cui.run();
	cui.waitForClose( cui );
}

public static void main( String args[] )
{
	String username, password, dbname;
	String host, port;
	int debuglevel = 0;

	int i;
	for( i=0; i<args.length; i++ )
	{
		if ( args[i].equals("-debug") )
		{
			debuglevel = 1;
		}
	}

	Debug.setprintlevel(debuglevel);

	username = System.getProperty( "dbuser" );
	password = System.getProperty( "dbpassword" );
	dbname = System.getProperty( "dbname" );
	host = System.getProperty( "dbhost" );
	port = System.getProperty( "dbport" );

	SQLtool sqltool;
	String propfile;
	propfile = System.getProperty("dbinfo");
	if ( propfile != null )
	{
		sqltool = new SQLtool( propfile );
	}
	else
		sqltool = new SQLtool( username, password, dbname, host, port );

	sqltool.run();


	System.exit(0);

}

private String processSQLCommand(String csql)
{
	Connection c = dbconnection;
	if ( c == null )
		return "No connection";
	Statement st = null;
	String ret = "unknown error";
	int r = -1;

	try {
		st = c.createStatement();
		if ( st == null )
			ret = "internal error";
		else
		{
			r = st.executeUpdate( csql );
			ret = "executed SQL command - r=" + r;
			st.close();
		}
	}
	catch( SQLException sx )
	{
		lastMessage = sx.getMessage();
		ret = "error in db command: " + sx.getMessage();
	}

	return ret;
}

private String processSQLQuery(String csql)
{
	Connection c = dbconnection;
	if ( c == null )
		return "No connection";
	Statement st = null;
	ResultSet rs = null;
	ResultSetMetaData rsmd = null;

	String ret = "Columns: ";
	try {
		st = c.createStatement();
		if ( st == null )
			return "internal error";
		rs = st.executeQuery( csql );
		rsmd = rs.getMetaData();

		if ( rsmd == null )
			return "no metadata in result";

		int i;
		int ncolumns = rsmd.getColumnCount();
		StringBuffer sb = new StringBuffer();
		for(i=1; i<=ncolumns; i++ )
		{
			sb.append( rsmd.getColumnName(i) );
			sb.append(" ");
		}
		sb.append("\n");
		sb.append("==================================\n");
		rs.beforeFirst();
		while( rs.next() )
		{
			for(i=1; i<=ncolumns; i++ )
			{
				sb.append( rs.getString(i) );
				sb.append(" ");
			}
			sb.append("\n");
		}
		ret = sb.toString();

		st.close();
	}
	catch( SQLException sx )
	{
		lastMessage = sx.getMessage();
		return "error in db command: " + sx.getMessage();
	}

	return ret;
}

private String printTablenames()
{
	StringBuffer sb = new StringBuffer();
	Enumeration en;
	en = m_tablenames.elements();
	while( en.hasMoreElements() )
	{
		sb.append( (String)en.nextElement() );
		sb.append("\n");
	}
	return sb.toString();
}

public static String SQLTypetoString( int t )
{
	String ret = "unknown type: " + t;
	switch( t )
	{
		case java.sql.Types.INTEGER:
			ret = "Integer"; break;
		case java.sql.Types.CHAR:
			ret = "Character"; break;
		case java.sql.Types.VARCHAR:
			ret = "Character String"; break;
		case java.sql.Types.ARRAY:
			ret = "Array"; break;
	}
	return ret;
}

private String getTableInfo( String name )
{
	ResultSet rs = null;
	StringBuffer sb = new StringBuffer();
	String ret = name + " --> ERR";

	try {
		rs = dbmeta.getColumns(null, null, name, null);
		while(  rs.next() )
		{
			sb.append( rs.getString(3) );
			sb.append( " " );
			sb.append( rs.getString(4) );
			sb.append( " " );
			sb.append( SQLTypetoString( rs.getInt(5)) );
			sb.append( "\n" );
		}
		ret = sb.toString();
	}
	catch( SQLException sx )
	{
		lastMessage = sx.getMessage();
		ret = "Exception: " + sx.getMessage();
	}

	return ret;
}

private static String helptext =
"Commands:\n"
+ "open - opens connection to database\n"
+ "close - closes connection to database\n"
+ "loadconfig filename - loads connection info\n"
+ "showdatabase - shows tables in database\n"
+ "showtable tablename - shows given table in database\n"
+ "query [full-SQL-select] - perform query\n"
+ "sqlcommand [full-SQL-insert,delete,update] - perform modification\n"
;

/**
* implements CommandProcessor
*/
public String processCommand(String command )
{
	StringTokenizer stk = new StringTokenizer(command);
	int nc = stk.countTokens();
	if ( nc == 0 )
		return "Nothing";
	String ret = "not yet";
	String cmd = stk.nextToken();
	String arg1, arg2;
	Debug.print( "cmd: " + cmd );
	StringBuffer sb = new StringBuffer();

	if ( cmd.equals("open") )
	{
		if ( openConnection() )
		{
			sb.append("OK\n");
			sb.append(printTablenames());
			ret = sb.toString();
		}
		else
			ret = "Error opening connection: " + lastMessage;
	}
	else if ( cmd.equals("close") )
	{
		closeConnection();
		ret = "Closed";
	}
	else if ( cmd.equals("query") )
	{
		String csql = command.substring(6);
		ret = processSQLQuery(csql);
	}
	else if ( cmd.equals("sqlcommand") )
	{
		String cs = command.substring(11);
		ret = processSQLCommand(cs);
	}
	else if ( cmd.equals("showtable") )
	{
		if ( stk.hasMoreTokens() )
		{
			arg1 = stk.nextToken();
			ret = getTableInfo( arg1 );
		}
		else
		{
			ret = "two arguments needed";
		}
	}
	else if ( cmd.equals("help") )
	{
		ret = helptext;
	}
	else if ( cmd.equals("loadconfig") )
	{
		if ( stk.hasMoreTokens() )
		{
			arg1 = stk.nextToken();
			if ( loadConnectionInfo( arg1 ) )
			{
				ret = "OK";
			}
			else
				ret = lastMessage;
		}
		else
		{
			ret = "two arguments needed";
		}
	}
	else if ( cmd.equals("showdatabase") )
	{
		ret = printTablenames();
	}
	return ret;
}

}

3.4. Libraries: util, io, net, sql, naming, security, crypto, CORBA, rmi, xml

java.lang: the main package

This contains basic data type as objects as well as String class. Also important is Thread and ThreadGroup supplying access to tricky threading functionality on UNIX. Important: Class and ClassLoader are objects representing code and allowing one to control the code loading process.

Object is the implicit base of all other class objects. You can instatiate a base object to construct a plain synchronization object - see code Event.java

package tjg.util;
/**
Implementation of a convenient Event object
*/

public class Event {
private boolean bSignaled = false;
private boolean bAutomatic = false;

public Event()
{
}

public Event(boolean b)
{
	bAutomatic = b;
}

public synchronized boolean waitForEvent( int timeout )
{
	// FIX here - make use of the timeout - now ignored
    // and treated as infinite
	try {
	while ( !bSignaled )
	{
		wait();
	}
	} catch( InterruptedException e)
	{}
	if ( bAutomatic )
		bSignaled = false;
	return true;
}

public synchronized void set()
{
	bSignaled = true;
	notifyAll();
}

public synchronized void reset()
{
	bSignaled = false;
}

}

java.util: List, Stack, Hash, Set, Collection, Date, Calendar, StringTokenizer, gzip compression

java.io: Input and OutputStream - prefixed with File, Buffered, ByteArray, Object, Data - can be combined together for synchronous IO This is used for synchronous I/O semantics. The write methods on streams return void or throw exceptions and read methods return number of bytes read or throw.

Code example - stacking of IO streams:

try {
	InputStream is;
	if ( file_in == null )
		is = System.in;
	else
		is = new FileInputStream( file_in );
	BufferedReader br = new BufferedReader( new InputStreamReader( is, "UTF-8" ) );	}
	catch ( IOException iox )
	{
	}

java.net: Socket, ServerSocket, DatagramSocket, InetAddress, URL, URLConnection, HttpURLConnection - these objects have methods getInputStream and getOutputStream

java.sql: see above

java.naming: LDAP, JNDI access to remote objects see below

Example of an LDAP client:

import java.util.*;

import javax.naming.*;
import javax.naming.directory.*;

public class jndi_search {
public static String INITCTX = "com.sun.jndi.ldap.LdapCtxFactory";
public static String HOST = "ldap://localhost:389";
//public static String HOST = "ldap://204.200.45.32:389";
//public static String HOST = "ldap://localhost:389";
public static String SEARCH_BASE = "";
//public static String SEARCH_BASE = "ou=sales,o=Acme";
public static String SEARCH_FILTER = "(sn=Carter)";
public static String[] ATTR_FILTER = {"cn","sn","mail"};

// authentication
public static String MGR_DN = "uid=myname, ou=people, o=Airius.com";
public static String MGR_PW = "our_secret";

public static boolean bAuth = false;

private static String[] parseTokens( String s )
{
	StringTokenizer stk = new StringTokenizer( s );
	String r[] = new String[ stk.countTokens() ];
	int i = 0;
	while ( stk.hasMoreTokens() )
	{
		r[i++] = stk.nextToken();
	}
	return r;
}

public static void main(String args[] )
{
	int i;
	for( i=0; i<args.length; i++ )
	{
		if ( args[i].equals("-host") )
		{
			HOST = args[++i];
		}
		if ( args[i].equals("-sbase") )
		{
			SEARCH_BASE = args[++i];
		}
		if ( args[i].equals("-attr") )
		{
			ATTR_FILTER = parseTokens(args[++i]);
		}
		if ( args[i].equals("-sn") )
		{
			SEARCH_FILTER = "(sn=" + args[++i] + ")";
		}
	}

	Hashtable env = new Hashtable();

	env.put( Context.INITIAL_CONTEXT_FACTORY, INITCTX);
	env.put( Context.PROVIDER_URL, HOST);

	if ( bAuth )
	{
		env.put( Context.SECURITY_AUTHENTICATION, "simple");
		env.put( Context.SECURITY_PRINCIPAL, MGR_DN);
		env.put( Context.SECURITY_CREDENTIALS, MGR_PW);
	}

	try {
	DirContext ctx = new InitialDirContext(env);

	SearchControls constraints = new SearchControls();
	constraints.setSearchScope( SearchControls.SUBTREE_SCOPE );

	NamingEnumeration result = ctx.search(SEARCH_BASE, SEARCH_FILTER, constraints );

	while ( result.hasMore() )
	{
		SearchResult sr = (SearchResult)result.next();
		print(">====>");
		showResult( ctx, sr );
		print("<====<");
	}
	}
	catch ( Exception ex )
	{
		System.err.println( "Exc: " + ex );
		ex.printStackTrace();
	}
}

public static void showResult( DirContext ctx, SearchResult sr ) throws NamingException
{
	String dn = sr.getName();
	print( "SearchResult: " + dn.toString() );
	Attributes attrs;
	boolean b_all = false;
	if ( b_all )
	attrs = sr.getAttributes();
	else
	attrs = ctx.getAttributes( dn + SEARCH_BASE, ATTR_FILTER);
	NamingEnumeration ne = attrs.getAll();
	while ( ne.hasMore() )
	{
		Attribute attr = (Attribute)ne.next();
		String id = attr.getID();
		print("Attribute: " + id );
		Enumeration e = attr.getAll();
		while( e.hasMoreElements() )
		{
			String s = (String)e.nextElement();
			print( "\t" + s );
		}

	}
}

private static void print( String s )
{
	System.out.println( s );
}

}

java.security: keystore implementations, ACLs, message digests, signatures, Digest IO Streams

javax.crypto: ciphers (3DES), key generators (DSA), Cipher IO Streams

org.w3c.dom, org.xml.sax: interfaces to XML technology - parsers are implemented in javax.xml.parsers but they can also be loaded from third-party code complying with the abstract interface

org.omg.CORBA, java.rmi: CORBA and RMI story

CORBA is essentially an object-oriented incarnation of RPC that was supposed to be the basis of distributed language-independent computing. The is a programming language independent IDL (Interface Definition Language) which is used to specify interfaces. CORBA is supported in Java since version 1.2 but only in version 1.4 the ORB (Object Request Broker) is based on POA (Portable Object Adapter) which controls how a server object (servant) is plugged into the system. The previous form of the Object Adapter allowed for inconsistencies between vendor implementations hurting the adoption of CORBA.CORBA uses a standard transport level protocol called IIOP.

Sun did not like the situation and implemented RMI (Remote Method Invocation) in Java 1.1 making it available only to Java programs. It works similarly to CORBA except it does not allow programming languages other than Java and it uses a proprietary network level protocol. The internal middlware architacture is also simplified to take advantage of the language uniformity bewtween the client and the server. This is used in distributed garbage collection and in generation of client/server stubs directly from Java code rather than from IDL.

Both CORBA and RMI take advantage of naming services through JNDI whereby clients locate server object. A server who wants to make a service object available binds it into a JNDI naming context.

abstractions - approach to let third party software implement functionality conforming to the abstract prescription - see example print spec http://java.sun.com/j2se/1.4.1/docs/api/ - see diagram abstraction pattern

3.5. New with 1.4 - asynchronous I/O, regular expressions

java.util.regex: Pattern object is first compiled - this creates a Matcher object which is then used to generate matches in a string

java.nio: buffers and channels are used to manage asynchrounous I/O operations

3.6. Example - ClassLoader

Example showing code that defines the abstract method - this is odler ClassLoader spec in JDK 1.1:

package tjg.loader;
....

// define abstract method
public class Loader extends ClassLoader {
....
// define abstract method
public synchronized Class loadClass( String name, boolean resolve )
	throws ClassNotFoundException
{
	Debug.print( ">>>> loadClass for " + name );
	Class c = null;
	ZippedClassEntry zip = null;

	// the class is part of java and loads by itself
	if ( name.startsWith( "java" ) )
	{
		c = Class.forName( name );
		Debug.print("<<<< loadClass: using forName " + name);
		return c;
	}

	// try to check if it is already loaded
	c = (Class)loadedclasscache.get(name);

	if ( c != null )
	{
		Debug.print("<<<< loadClass: already loaded " + name);
		return c;
	}

	// try to check if the class data is already in memory
	zip = (ZippedClassEntry)zippedentrycache.get(name);

	// if the class data is not yet in memory
	// load the archive data and check after each load
	// if the class was there
	if ( zip == null )
	{
		int ia;
		for( ia = first_not_loaded; ia<archives_vector.size(); ia++ )
		{
			String archive = (String)archives_vector.elementAt(ia);

			Debug.print("loadClass: loading archive " + archive);

			loadArchive(archive);
			first_not_loaded = ia+1;

			zip = (ZippedClassEntry)zippedentrycache.get(name);

			if ( zip != null )
				break;

		}
	}

	// we get the class data in a zip entry - ie loaded from archives
	if ( zip != null )
	{
		Debug.print("loadClass: ZippedClass found -- calling makeClassFromZipEntry " + zip.name );
		c = makeClassFromZipEntry( zip );
	}

	if ( c != null )
	{
		Debug.print("loadClass: zip load successful -- archives loaded " + first_not_loaded );
	}

	// we went through the archives and the class is not there
	// we will try to load a class file at codebase_local and then remote
	if ( c == null )
	{
		Debug.print( "loadClass: will try to load a class file -- archives " + first_not_loaded);

		c = makeClassFromFile( codebase_local, name );
		if ( c == null )
			c = makeClassFromFile( codebase, name );
	}

	if ( c == null )
	{
		Debug.print( "<<<< loadClass FAILED " + name);
		return null;
	}

	loadedclasscache.put(name, c);

	if ( resolve )
	{
		Debug.print( "Call resolveClass " + name );
		resolveClass( c );
		Debug.print( "Call resolveClass returned for " + name );
	}

	Debug.print( "<<<< loadClass full load " + name);
	return c;
}

...
}