API documentation is in http://java.sun.com/j2se/1.4.1/docs/api/
Basic programming language principles
Objects and classes are everywhere - all functions are methods of class objects.
Simple numerical types are signed - except char, arrays are special types of objects
There are no pointers - simple types are passed to and returned from methods by value, objects by reference, in effect there is no access to virtual memory
Classes have constructors but no destructors, objects with no references to them are garbage collected - this is the most difficult aspect of JVM implementation
C++ features of dubious value are not supported - operator overloading, private or multiple inheritance schemes
C++ features of great value: abstract classes, interfaces, inheritance and method overloading
Rigorous enforcement of exception handling - each method must declare exceptions that it may throw and when it is invoked the caller must either handle it or declare that it may throw this exception
Programming examples
Simple program parsing a text file - tonative.java
Complex XML Editor - DomDoc.java
Database access using JDBC - SQLTool.java
Libraries: util, io, net, sql, naming, security, crypto, CORBA, rmi, xml
Abstractions specifying interfaces
New with 1.4 - asynchronous I/O, regular expressions
Advanced language features
Class - is also a class object representing code
ClassLoader - instantiates Class objects, programmer can create many instances of loader - example code Loader
Loose linkage - program will run with "unresolved references", you can test if classes can be loaded at runtime
Reflection -can use to control invocation; also methods to examine own stack, analyze methods and fields provided by a Class object
JNI - can be used to easily plug in native code
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; } }
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; } .... }
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; } }
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
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
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; } ... }