Schema.java :  » Database-ORM » Torque » com » workingdogs » village » Java Open Source

Java Open Source » Database ORM » Torque 
Torque » com » workingdogs » village » Schema.java
package com.workingdogs.village;

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;

import java.util.Enumeration;
import java.util.Hashtable;

/**
 * The Schema object represents the <a href="Column.html">Columns</a> in a database table. It contains a collection of <a
 * href="Column.html">Column</a> objects.
 *
 * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
 * @author John D. McNally
 * @version $Revision: 568 $
 */
public final class Schema
{
    /** TODO: DOCUMENT ME! */
    private String tableName;

    /** TODO: DOCUMENT ME! */
    private String columnsAttribute;

    /** TODO: DOCUMENT ME! */
    private int numberOfColumns;

    /** TODO: DOCUMENT ME! */
    private Column [] columns;

    /** TODO: DOCUMENT ME! */
    private static Hashtable schemaCache = new Hashtable();

    /**
     * This attribute is used to complement columns in the event that this schema represents more than one table.  Its keys are
     * String contains table names and its elements are Hashtables containing columns.
     */
    private Hashtable tableHash = null;

    /** TODO: DOCUMENT ME! */
    private boolean singleTable = true;

    /**
     * A blank Schema object
     */
    public Schema()
    {
        this.tableName = "";
        this.columnsAttribute = null;
        this.numberOfColumns = 0;
    }

    /**
     * Creates a Schema with all columns
     *
     * @param conn
     * @param tableName
     *
     * @return an instance of myself
     *
     * @exception SQLException
     * @exception DataSetException
     */
    public Schema schema(Connection conn, String tableName)
            throws SQLException, DataSetException
    {
        return schema(conn, tableName, "*");
    }

    /**
     * Creates a Schema with the named columns in the columnsAttribute
     *
     * @param conn
     * @param tableName
     * @param columnsAttribute
     *
     * @return an instance of myself
     *
     * @exception SQLException
     * @exception DataSetException
     */
    public synchronized Schema schema(Connection conn, String tableName, String columnsAttribute)
            throws SQLException, DataSetException
    {
        if (columnsAttribute == null)
        {
            columnsAttribute = "*";
        }

        Statement stmt = null;

        try
        {
            String keyValue = conn.getMetaData().getURL() + tableName;
            Schema tableSchema = (Schema) schemaCache.get(keyValue);

            if (tableSchema == null)
            {
                String sql = "SELECT " + columnsAttribute + " FROM " + tableName + " WHERE 1 = -1";
                stmt = conn.createStatement();

                ResultSet rs = stmt.executeQuery(sql);

                if (rs != null)
                {
                    tableSchema = new Schema();
                    tableSchema.setTableName(tableName);
                    tableSchema.setAttributes(columnsAttribute);
                    tableSchema.populate(rs.getMetaData(), tableName);
                    schemaCache.put(keyValue, tableSchema);
                }
                else
                {
                    throw new DataSetException("Couldn't retrieve schema for " + tableName);
                }
            }

            return tableSchema;
        }
        finally
        {
            if (stmt != null)
            {
                stmt.close();
            }
        }
    }

    /**
     * Appends data to the tableName that this schema was first created with.
     *
     * <P></p>
     *
     * @param app String to append to tableName
     *
     * @see TableDataSet#tableQualifier(java.lang.String)
     */
    void appendTableName(String app)
    {
        this.tableName = this.tableName + " " + app;
    }

    /**
     * List of columns to select from the table
     *
     * @return the list of columns to select from the table
     */
    public String attributes()
    {
        return this.columnsAttribute;
    }

    /**
     * Returns the requested Column object at index i
     *
     * @param i
     *
     * @return the requested column
     *
     * @exception DataSetException
     */
    public Column column(int i)
            throws DataSetException
    {
        if (i == 0)
        {
            throw new DataSetException("Columns are 1 based");
        }
        else if (i > numberOfColumns)
        {
            throw new DataSetException("There are only " + numberOfColumns() + " available!");
        }

        try
        {
            return columns[i];
        }
        catch (Exception e)
        {
            throw new DataSetException("Column number: " + numberOfColumns() + " does not exist!");
        }
    }

    /**
     * Returns the requested Column object by name
     *
     * @param colName
     *
     * @return the requested column
     *
     * @exception DataSetException
     */
    public Column column(String colName)
            throws DataSetException
    {
        return column(index(colName));
    }

    /**
     * Returns the requested Column object by name
     *
     * @param colName
     *
     * @return the requested column
     *
     * @exception DataSetException
     */
    public Column getColumn(String colName)
            throws DataSetException
    {
        int dot = colName.indexOf('.');

        if (dot > 0)
        {
            String table = colName.substring(0, dot);
            String col = colName.substring(dot + 1);

            return getColumn(table, col);
        }

        return column(index(colName));
    }

    /**
     * Returns the requested Column object belonging to the specified table by name
     *
     * @param tableName
     * @param colName
     *
     * @return the requested column, null if a column by the specified name does not exist.
     *
     * @exception DataSetException
     */
    public Column getColumn(String tableName, String colName)
            throws DataSetException
    {
        return (Column) ((Hashtable) tableHash.get(tableName)).get(colName);
    }

    /**
     * Returns an array of columns
     *
     * @return an array of columns
     */
    Column [] getColumns()
    {
        return this.columns;
    }

    /**
     * returns the table name that this Schema represents
     *
     * @return the table name that this Schema represents
     *
     * @throws DataSetException TODO: DOCUMENT ME!
     */
    public String getTableName()
            throws DataSetException
    {
        if (singleTable)
        {
            return tableName;
        }
        else
        {
            throw new DataSetException("This schema represents several tables.");
        }
    }

    /**
     * returns all table names that this Schema represents
     *
     * @return the table names that this Schema represents
     */
    public String [] getAllTableNames()
    {
        Enumeration e = tableHash.keys();
        String [] tableNames = new String[tableHash.size()];

        for (int i = 0; e.hasMoreElements(); i++)
        {
            tableNames[i] = (String) e.nextElement();
        }

        return tableNames;
    }

    /**
     * Gets the index position of a named column.  If multiple tables are represented and they have columns with the same name,
     * this method returns the first one listed, if the table name is not specified.
     *
     * @param colName
     *
     * @return the requested column index integer
     *
     * @exception DataSetException
     */
    public int index(String colName)
            throws DataSetException
    {
        int dot = colName.indexOf('.');

        if (dot > 0)
        {
            String table = colName.substring(0, dot);
            String col = colName.substring(dot + 1);

            return index(table, col);
        }

        for (int i = 1; i <= numberOfColumns(); i++)
        {
            if (columns[i].name().equalsIgnoreCase(colName))
            {
                return i;
            }
        }

        throw new DataSetException("Column name: " + colName + " does not exist!");
    }

    /**
     * Gets the index position of a named column.
     *
     * @param tableName
     * @param colName
     *
     * @return the requested column index integer
     *
     * @exception DataSetException
     */
    public int index(String tableName, String colName)
            throws DataSetException
    {
        for (int i = 1; i <= numberOfColumns(); i++)
        {
            if (columns[i].name().equalsIgnoreCase(colName) && columns[i].getTableName().equalsIgnoreCase(tableName))
            {
                return i;
            }
        }

        throw new DataSetException("Column name: " + colName + " does not exist!");
    }

    /**
     * Checks to see if this DataSet represents one table in the database.
     *
     * @return true if only one table is represented, false otherwise.
     */
    public boolean isSingleTable()
    {
        return singleTable;
    }

    /**
     * Gets the number of columns in this Schema
     *
     * @return integer number of columns
     */
    public int numberOfColumns()
    {
        return this.numberOfColumns;
    }

    /**
     * Internal method which populates this Schema object with Columns.
     *
     * @param meta The meta data of the ResultSet used to build this Schema.
     * @param tableName The name of the table referenced in this schema, or null if unknown or multiple tables are involved.
     *
     * @exception SQLException
     * @exception DataSetException
     */
    void populate(ResultSetMetaData meta, String tableName)
            throws SQLException, DataSetException
    {
        this.numberOfColumns = meta.getColumnCount();
        columns = new Column[numberOfColumns() + 1];

        for (int i = 1; i <= numberOfColumns(); i++)
        {
            Column col = new Column();
            col.populate(meta, i, tableName);
            columns[i] = col;

            if ((i > 1) && !col.getTableName().equalsIgnoreCase(columns[i - 1].getTableName()))
            {
                singleTable = false;
            }
        }

        // Avoid creating a Hashtable in the most common case where only one
        // table is involved, even though this makes the multiple table case
        // more expensive because the table/column info is duplicated.
        if (singleTable)
        {
            // If available, use a the caller supplied table name.
            if ((tableName != null) && (tableName.length() > 0))
            {
                setTableName(tableName);
            }
            else
            {
                // Since there's only one table involved, attempt to set the
                // table name to that of the first column.  Sybase jConnect
                // 5.2 and older will fail, in which case we are screwed.
                try
                {
                    setTableName(meta.getTableName(1));
                }
                catch (Exception e)
                {
                    setTableName("");
                }
            }
        }
        else
        {
            tableHash = new Hashtable((int) ((1.25 * numberOfColumns) + 1));

            for (int i = 1; i <= numberOfColumns(); i++)
            {
                if (tableHash.containsKey(columns[i].getTableName()))
                {
                    ((Hashtable) tableHash.get(columns[i].getTableName())).put(columns[i].name(), columns[i]);
                }
                else
                {
                    Hashtable columnHash = new Hashtable((int) ((1.25 * numberOfColumns) + 1));
                    columnHash.put(columns[i].name(), columns[i]);
                    tableHash.put(columns[i].getTableName(), columnHash);
                }
            }
        }
    }

    /**
     * Sets the columns to select from the table
     *
     * @param attributes comma separated list of column names
     */
    void setAttributes(String attributes)
    {
        this.columnsAttribute = attributes;
    }

    /**
     * Sets the table name that this Schema represents
     *
     * @param tableName
     */
    void setTableName(String tableName)
    {
        this.tableName = tableName;
    }

    /**
     * returns the table name that this Schema represents
     *
     * @return the table name that this Schema represents
     *
     * @throws DataSetException TODO: DOCUMENT ME!
     */
    public String tableName()
            throws DataSetException
    {
        return getTableName();
    }

    /**
     * This returns a representation of this Schema
     *
     * @return a string
     */
    public String toString()
    {
        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        PrintWriter out = new PrintWriter(bout);
        out.print('{');

        for (int i = 1; i <= numberOfColumns; i++)
        {
            out.print('\'');

            if (!singleTable)
            {
                out.print(columns[i].getTableName() + '.');
            }

            out.print(columns[i].name() + '\'');

            if (i < numberOfColumns)
            {
                out.print(',');
            }
        }

        out.print('}');
        out.flush();

        return bout.toString();
    }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.