FileDocCategorySizeDatePackage
SimpleTextConnection.javaAPI DocExample26569Sat Feb 03 11:43:40 GMT 2001jdbc.SimpleText

SimpleTextConnection.java

//----------------------------------------------------------------------------
//
// Module:      SimpleTextConnection.java
//
// Description: Implementation of the JDBC Connection interface
//
// Author:      Karl Moss
//
// Copyright:   (C) 1996,1997 Karl Moss.  All rights reserved.
//              You may study, use, modify and distribute this example
//              for any purpose, provided that this copyright notice
//              appears in all copies.  This example is provided WITHOUT
//              WARRANTY either expressed or implied.
//----------------------------------------------------------------------------

package jdbc.SimpleText;

//----------------------------------------------------------------------------
// A Connection represents a session with a specific
// database. Within the context of a Connection, SQL statements are
// executed and results are returned.
//
// A Connection's database is able to provide information
// describing its tables, its supported SQL grammar, its stored
// procedures, the capabilities of this connection, etc. This
// information is obtained with the getMetaData method.
//
// Note: By default the Connection automatically commits
// changes after executing each statement. If auto commit has been
// disabled an explicit commit must be done or database changes will
// not be saved.
//----------------------------------------------------------------------------
// NOTE - this is an implementation of the JDBC API version 1.20
//---------------------------------------------------------------------------

import java.sql.*;
import java.io.*;
import java.util.Hashtable;
import java.util.StringTokenizer;

public class SimpleTextConnection
    extends       SimpleTextObject
    implements    SimpleTextIConnection
{

    //------------------------------------------------------------------------
    // initialize
    // Initialize the Connection object
    //------------------------------------------------------------------------

    public void initialize (
        SimpleTextIDriver driver,
        java.util.Properties info)
        throws SQLException
    {

        // Save the owning driver object

        ownerDriver = driver;

        // Get the security manager and see if we can write to a file.
        // If no security manager is present, assume that we are a trusted
        // application and have read/write privileges.

        canWrite = false;

        SecurityManager securityManager = System.getSecurityManager ();

        if (securityManager != null) {
            try {
                // Use some arbitrary file to check for file write privileges

                securityManager.checkWrite ("SimpleText_Foo");

                // Flag is set if no exception is thrown

                canWrite = true;
            }

            // If we can't write, an exception is thrown.  We'll catch
            // it and do nothing

            catch (SecurityException ex) {
            }
        }
        else {
            canWrite = true;
        }

        // Set our initial read-only flag

        setReadOnly(!canWrite);

        // Get the directory.  It will either be supplied with the URL, in
        //  the property list, or we'll use our current default

        String s = ownerDriver.getSubname();
        int slen = 0;

        if (s != null) {
            slen = s.length();
        }

        if (slen == 0) {
            s = info.getProperty("Directory");
        }

        if (s == null) {
            s = System.getProperty("user.dir");
        }

        setCatalog(s);
    }

    //------------------------------------------------------------------------
    // createStatement - JDBC API
    //
    // SQL statements without parameters are normally
    // executed using Statement objects. If the same SQL statement
    // is executed many times it is more efficient to use a
    // PreparedStatement
    //
    // Returns a new Statement object
    //------------------------------------------------------------------------

    public Statement createStatement()
        throws SQLException
    {
        if (traceOn()) {
            trace("Creating new SimpleTextStatement");
        }

        // Create a new Statement object

        SimpleTextStatement stmt = new SimpleTextStatement();

        // Initialize the statement

        stmt.initialize (this);

        return stmt;
    }

    //------------------------------------------------------------------------
    // prepareStatement - JDBC API
    //
    // A SQL statement with or without IN parameters can be
    // pre-compiled and stored in a PreparedStatement object. This
    // object can then be used to efficiently execute this statement
    // multiple times.
    //
    // Note: This method is optimized for handling
    // parametric SQL statements that benefit from precompilation. If
    // the driver supports precompilation, prepareStatement will send
    // the statement to the database for precompilation. Some drivers
    // may not support precompilation. In this case, the statement may
    // not be sent to the database until the PreparedStatement is
    // executed.  This has no direct affect on users; however, it does
    // affect which method throws certain SQLExceptions.
    //
    //    sql        a SQL statement that may contain one or more '?' IN
    //            parameter placeholders
    //
    // Returns a new PreparedStatement object containing the
    //            pre-compiled statement
    //------------------------------------------------------------------------

    public PreparedStatement prepareStatement(
        String sql)
        throws SQLException
    {
        if (traceOn()) {
            trace("@prepareStatement (sql=" + sql + ")");
        }

        // Create a new PreparedStatement object

        SimpleTextPreparedStatement ps = new SimpleTextPreparedStatement();

        // Initialize the PreparedStatement

        ps.initialize(this, sql);

        return ps;
    }

    //------------------------------------------------------------------------
    // prepareCall - JDBC API
    //
    // A SQL stored procedure call statement is handled by creating a
    // CallableStatement for it. The CallableStatement provides
    // methods for setting up its IN and OUT parameters, and
    // methods for executing it.
    //
    // Note: This method is optimized for handling stored
    // procedure call statements. Some drivers may send the call
    // statement to the database when the prepareCall is done; others
    // may wait until the CallableStatement is executed. This has no
    // direct affect on users; however, it does affect which method
    // throws certain SQLExceptions.
    //
    //    sql        a SQL statement that may contain one or more '?'
    //            parameter placeholders
    //
    // Returns a new CallableStatement object containing the
    //            pre-compiled SQL statement
    //------------------------------------------------------------------------

    public CallableStatement prepareCall(
        String sql)
        throws SQLException
    {
        if (traceOn()) {
            trace("@prepareCall (sql=" + sql + ")");
        }

        // The SimpleText driver does not support callable statements

        throw new SQLException("Driver does not support this function");
    }

    //------------------------------------------------------------------------
    // nativeSQL - JDBC API
    //
    // A driver may convert the JDBC sql grammar into its system's
    // native SQL grammar prior to sending it; nativeSQL returns the
    // native form of the statement that the driver would have sent.
    //
    //    sql        a SQL statement that may contain one or more '?'
    //            parameter placeholders
    //
    // Returns the native form of this statement
    //------------------------------------------------------------------------

    public String nativeSQL(
        String sql)
        throws SQLException
    {

        // For the SimpleText driver, simply return the original
        // sql statement.  Other drivers will need to expand escape
        // sequences here.

        return sql;
    }

    //------------------------------------------------------------------------
    // setAutoCommit - JDBC API
    //
    // If a connection is in auto-commit mode, then all its SQL
    // statements will be executed and committed as individual
    // transactions.  Otherwise, its SQL statements are grouped into
    // transactions that are terminated by either commit() or
    // rollback().  By default, new connections are in auto-commit
    // mode.
    //
    //    autoCommit    true enables auto-commit; false disables
    //                auto-commit.
    //------------------------------------------------------------------------

    public void setAutoCommit(
        boolean autoCommit)
        throws SQLException
    {
        if (traceOn()) {
            trace("@setAutoCommit (autoCommit=" + autoCommit + ")");
        }

        // The SimpleText driver is always in auto-commit mode (it does
        // not support transactions).  Throw an exception if an attempt
        // is made to change the mode

        if (autoCommit == false) {
            throw DriverNotCapable();
        }
    }

    //------------------------------------------------------------------------
    // getAutoCommit - JDBC API
    //
    // Get the current auto-commit state.
    // Returns the current state of auto-commit mode.
    //------------------------------------------------------------------------

    public boolean getAutoCommit()
        throws SQLException
    {
        // The SimpleText driver is always in auto-commit mode (it does
        // not support transactions)

        return true;
    }

    //------------------------------------------------------------------------
    // commit - JDBC API
    //
    // Commit makes all changes made since the previous
    // commit/rollback permanent and releases any database locks
    // currently held by the Connection.
    //------------------------------------------------------------------------

    public void commit()
        throws SQLException
    {
        // No-op for the SimpleText driver
    }

    //------------------------------------------------------------------------
    // rollback - JDBC API
    //
    // Rollback drops all changes made since the previous
    // commit/rollback and releases any database locks currently held
    // by the Connection.
    //------------------------------------------------------------------------

    public void rollback()
        throws SQLException
    {
        // No-op for the SimpleText driver
    }

    //------------------------------------------------------------------------
    // close - JDBC API
    //
    // In some cases, it is desirable to immediately release a
    // Connection's database and JDBC resources instead of waiting for
    // them to be automatically released; the close method provides this
    // immediate release.
    //------------------------------------------------------------------------

    public void close()
        throws SQLException
    {
        connectionClosed = true;
    }

    //------------------------------------------------------------------------
    // isClosed - JDBC API
    //
    // Check if a Connection is closed
    //------------------------------------------------------------------------

    public boolean isClosed()
        throws SQLException
    {
        return connectionClosed;
    }

    //------------------------------------------------------------------------
    // getMetaData - JDBC API
    //
    // A Connection's database is able to provide information
    // describing its tables, its supported SQL grammar, its stored
    // procedures, the capabilities of this connection, etc. This
    // information is made available through a DatabaseMetaData
    // object.
    //
    // Returns a DatabaseMetaData object for this Connection
    //------------------------------------------------------------------------

    public DatabaseMetaData getMetaData()
        throws SQLException
    {
        SimpleTextDatabaseMetaData dbmd = new SimpleTextDatabaseMetaData ();

        dbmd.initialize(this);

        return dbmd;
    }

    //------------------------------------------------------------------------
    // setReadOnly - JDBC API
    //
    // You can put a connection in read-only mode as a hint to enable
    // database optimizations.
    //
    // Note: setReadOnly cannot be called while in the
    // middle of a transaction.
    //------------------------------------------------------------------------

    public void setReadOnly(
        boolean readOnly)
        throws SQLException
    {

        // If we are trying to set the connection not read only (allowing
        // writes), and this connection does not allow writes, throw
        // an exception

        if ((readOnly == false) &&
            (canWrite == false)) {
            throw DriverNotCapable();
        }

        // Set the readOnly attribute for the SimpleText driver.  If set,
        // the driver will not allow updates or deletes to any text file

        this.readOnly = readOnly;
    }

    //------------------------------------------------------------------------
    // isReadOnly - JDBC API
    //
    // Test if the connection is in read-only mode
    //------------------------------------------------------------------------

    public boolean isReadOnly()
        throws SQLException
    {
        return readOnly;
    }

    //------------------------------------------------------------------------
    // setCatalog - JDBC API
    //
    // A sub-space of this Connection's database may be selected by setting a
    // catalog name. If the driver does not support catalogs it will
    // silently ignore this request.
    //------------------------------------------------------------------------

    public void setCatalog(String catalog)
        throws SQLException
    {
        if (traceOn()) {
            trace("@setCatalog(" + catalog + ")");
        }

        // If the last character is a separator, remove it

        if (catalog.endsWith("/") ||
            catalog.endsWith("\\")) {
            catalog = catalog.substring(0, catalog.length());
        }

        // Make sure this is a directory

        File dir = new File(catalog);

        if (!dir.isDirectory()) {
            throw new SQLException("Invalid directory: " + catalog);
        }

        this.catalog = catalog;
    }

    //------------------------------------------------------------------------
    // getCatalog
    // Returns the Connection's current catalog name
    //------------------------------------------------------------------------

    public String getCatalog()
        throws SQLException
    {
        return catalog;
    }

    //------------------------------------------------------------------------
    // setTransactionIsolation - JDBC API
    //
    // You can call this method to try to change the transaction
    // isolation level on a newly opened connection, using one of the
    // TRANSACTION_* values.
    //
    //    level    one of the TRANSACTION_* isolation values with the
    //            exception of TRANSACTION_NONE; some databases may not support
    //            other values
    //------------------------------------------------------------------------

    public void setTransactionIsolation(
        int level)
        throws SQLException
    {
        if (traceOn()) {
            trace("@setTransactionIsolation (level=" + level + ")");
        }

        // Throw an exception if the transaction isolation is being
        // changed to something different

        if (level != TRANSACTION_NONE) {
            throw DriverNotCapable();
        }
    }

    //------------------------------------------------------------------------
    // getTransactionIsolation - JDBC API
    //
    // Get this Connection's current transaction isolation mode
    //------------------------------------------------------------------------

    public int getTransactionIsolation()
        throws SQLException
    {
        // The SimpleText driver does not support transactions

        return TRANSACTION_NONE;
    }

    //------------------------------------------------------------------------
    // getWarnings - JDBC API
    //
    // The first warning reported by calls on this Connection is
    // returned.
    //
    // Note: Subsequent warnings will be chained to this SQLWarning.
    //------------------------------------------------------------------------

    public SQLWarning getWarnings()
        throws SQLException
    {
        // No warnings exist for the SimpleText driver.  Always return
        // null

        return null;
    }

    //------------------------------------------------------------------------
    // clearWarnings - JDBC API
    //
    // After this call getWarnings returns null until a new warning is
    // reported for this Connection.
    //------------------------------------------------------------------------

    public void clearWarnings()
        throws SQLException
    {
        // No-op
    }

    //------------------------------------------------------------------------
    // parseSQL
    // Given a sql statement, parse it and return a String array with each
    // keyword.  This is a VERY simple parser.
    //------------------------------------------------------------------------

    public String[] parseSQL(
        String sql)
    {
        String keywords[] = null;

        // Create a new Hashtable to keep our words in.  This way, we can
        // build the Hashtable as we go, then create a String array
        // once we know how may words are present

        java.util.Hashtable table = new java.util.Hashtable();
        int count = 0;

        // Current offset in the sql string

        int offset = 0;

        // Get the first word from the sql statement

        String word = parseWord(sql.substring(offset));

        // Loop while more words exist in the sql string

        while (word.length() > 0) {

            // Increment the offset pointer

            offset += word.length();

            // Trim all leading and trailing spaces

            word = word.trim();

            if (word.length() > 0) {

                // Put the word in our hashtable

                table.put(new Integer(count), word);
                count++;
            }

            // Get the next word

            word = parseWord(sql.substring(offset));
        }

        // Create our new String array with the proper number of elements

        keywords = new String[count];

        // Copy the words from the Hashtable to the String array

        for (int i = 0; i < count; i++) {
            keywords[i] = (String) table.get(new Integer(i));
        }
        return keywords;
    }

    //------------------------------------------------------------------------
    // getTables
    // Given a directory and table pattern, return a Hashtable containing
    // SimpleTextTable entries
    //------------------------------------------------------------------------

    public Hashtable getTables(
        String dir,
        String table)
    {
        Hashtable list = new Hashtable();

        // Create a FilenameFilter object.  This object will only allow
        // files with the .SDF extension to be seen

        FilenameFilter filter = new SimpleTextEndsWith(
                    SimpleTextDefine.DATA_FILE_EXT);


        File file = new File(dir);

        if (file.isDirectory()) {

            // List all of the files in the directory with the .SDF extension

            String entries[] = file.list(filter);
            SimpleTextTable tableEntry;

            // Create a SimpleTextTable entry for each, and put in
            // the Hashtable

            for (int i = 0; i < entries.length; i++) {

                // A complete driver needs to further filter the table
                // name here

                tableEntry = new SimpleTextTable(dir, entries[i]);
                list.put(new Integer(i), tableEntry);
            }
        }

        return list;
    }

    //------------------------------------------------------------------------
    // getColumns
    // Given a directory and table name, return a Hashtable containing
    // SimpleTextColumn entries.  Returns null if the table is not found
    //------------------------------------------------------------------------

    public Hashtable getColumns(
        String dir,
        String table)
    {
        Hashtable list = new Hashtable();

        // Create the full path to the table

        String fullPath = dir + "/" + table + SimpleTextDefine.DATA_FILE_EXT;

        File f = new File (fullPath);

        // If the file does not exist, return null

        if (!f.exists()) {
            if (traceOn()) {
                trace("File does not exist: " + fullPath);
            }
            return null;
        }

        String line = "";

        // Create a random access object and read the first line
        // Create the table

        try {
            RandomAccessFile raf = new RandomAccessFile(f, "r");

            // Read the first line, which is the column definitions

            line = raf.readLine();
			raf.close();

        }
        catch (IOException ex) {
            if (traceOn()) {
                trace("Unable to read file: " + fullPath);
            }
            return null;
        }

        // Now, parse the line.  First, check for the branding

        if (!line.startsWith(SimpleTextDefine.DATA_FILE_EXT)) {
            if (traceOn()) {
                trace("Invalid file format: " + fullPath);
            }
            return null;
        }

        line = line.substring(SimpleTextDefine.DATA_FILE_EXT.length());

        // Now we can use the StringTokenizer, since we know that the
        // column names can't contain data within quotes (this is why
        // we can't use the StringTokenizer with SQL statements)

        StringTokenizer st = new StringTokenizer(line, ",");

        String columnName;
        int columnType;
        int precision;
        SimpleTextColumn column;
        int count = 0;
        boolean searchable;
        int displaySize;
        String typeName;

        // Loop while more tokens exist

        while (st.hasMoreTokens()) {
            columnName = (st.nextToken()).trim();

            if (columnName.length() == 0) {
                continue;
            }

            if (columnName.startsWith(SimpleTextDefine.COL_TYPE_NUMBER)) {
                columnType = Types.INTEGER;
                precision = SimpleTextDefine.MAX_INTEGER_LEN;
                columnName = columnName.substring(
                            SimpleTextDefine.COL_TYPE_NUMBER.length());
                displaySize = precision;
                typeName = "VARCHAR";
                searchable = true;
            }
            else if (columnName.startsWith(SimpleTextDefine.COL_TYPE_BINARY)) {
                columnType = Types.VARBINARY;
                precision = SimpleTextDefine.MAX_VARBINARY_LEN;
                columnName = columnName.substring(
                            SimpleTextDefine.COL_TYPE_BINARY.length());
                displaySize = precision * 2;
                typeName = "BINARY";
                searchable = false;
            } else {
                columnType = Types.VARCHAR;
                precision = SimpleTextDefine.MAX_VARCHAR_LEN;
                searchable = true;
                displaySize = precision;
                typeName = "NUMBER";
            }

            // Create a new column object and add to the Hashtable

            column = new SimpleTextColumn(columnName, columnType, precision);
            column.searchable = searchable;
            column.displaySize = displaySize;
            column.typeName = typeName;

            // The column number will be 1-based

            count++;

            // Save the absolute column number

            column.colNo = count;

            list.put(new Integer(count), column);
        }

        return list;
    }

    //------------------------------------------------------------------------
    // getDirectory
    // Given a directory filter (which may be null), format the directory
    // to use in a search.  The default connection directory may be returned
    //------------------------------------------------------------------------

    public String getDirectory(
        String directory)
    {
        String dir;

        if (directory == null) {
            dir = catalog;
        }
        else if (directory.length() == 0) {
            dir = catalog;
        }
        else {
            dir = directory;
            if (dir.endsWith("/") ||
                dir.endsWith("\\")) {
                dir = dir.substring(0, dir.length());
            }
        }

        return dir;
    }


    protected SimpleTextIDriver ownerDriver;// Pointer to the owning
                                            // Driver object

    protected boolean connectionClosed;        // true if the connection is
                                            // currently closed

    protected boolean readOnly;                // true if the connection is
                                            // read-only

    protected boolean canWrite;                // true if we are able to write
                                            // to files

    protected String catalog;                // Current catalog (qualifier)
                                            // for text files

}

//----------------------------------------------------------------------------
// This class is a simple FilenameFilter.  It defines the required accept()
// method to determine whether a specified file should be listed.  A file
// will be listed if its name ends with the specified extension.
//----------------------------------------------------------------------------

class SimpleTextEndsWith
    implements FilenameFilter
{
    public SimpleTextEndsWith(
        String extension)
    {
        ext = extension;
    }

    public boolean accept(
        File dir,
        String name)
    {
        if (name.endsWith(ext)) {
            return true;
        }
        return false;
    }

    protected String ext;
}