/* The contents of this file are subject to the license and copyright terms * detailed in the license directory at the root of the source tree (also * available online at http://fedora-commons.org/license/). */ package fedora.server.utilities; import java.io.IOException; import java.io.InputStream; import java.util.Iterator; import java.util.List; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import fedora.server.errors.InconsistentTableSpecException; /** * A holder of table specification information that helps in producing * RDBMS-generic DDL "CREATE TABLE" commands. * * <p>An application constructs a TableSpec without regard to the underlying * database kind, and then the TableSpec is converted to a DB-specific CREATE * TABLE DDL command by a DDLConverter before the command is issued via JDBC. * * @author Chris Wilper */ public class TableSpec { private final String m_name; private final List<ColumnSpec> m_columnSpecs; private final String m_primaryColumnName; private String m_type; /** * Constructs a TableSpec given a name, a set of ColumnSpecs, and the name * of the primary key column. * * @param name * The table name. * @param columnSpecs * ColumnSpec objects describing columns in the table. * @param primaryColumnName * The column that is the primary key for the table. * @throws InconsistentTableSpecException * if inconsistencies are detected in table specifications. */ public TableSpec(String name, List<ColumnSpec> columnSpecs, String primaryColumnName) throws InconsistentTableSpecException { m_name = name; m_columnSpecs = columnSpecs; m_primaryColumnName = primaryColumnName; assertConsistent(); } /** * Constructs a TableSpec given a name, a set of ColumnSpecs, the name of * the primary key column, and a table type. Table type specification is not * supported by all RDBMS software, and is usually software-specific. When a * tableSpec is used to create a table, if the type is understood it is * used. Otherwise it is ignored. * * @param name * The table name. * @param columnSpecs * ColumnSpec objects describing columns in the table. * @param primaryColumnName * The column that is the primary key for the table. * @param type * The table type. * @throws InconsistentTableSpecException * if inconsistencies are detected in table specifications. */ public TableSpec(String name, List<ColumnSpec> columnSpecs, String primaryColumnName, String type) throws InconsistentTableSpecException { m_name = name; m_columnSpecs = columnSpecs; m_primaryColumnName = primaryColumnName; m_type = type; assertConsistent(); } /** * Gets a TableSpec for each table element in the stream, where the stream * contains a valid XML document containing one or more table elements, * wrapped in the root element. * * <p> * Input is of the form: * * <pre> * <database> * <table name="<i>tableName</i>" primaryKey="<i>primaryColumnName</i>" type="<i>tableType</i>"> * <column name="<i>columnName</i>" * type="<i>typeSpec</i>" * autoIncrement="<i>isAutoIncremented</i>" * index="<i>indexName</i>" * notNull="<i>isNotNull</i>" * unique="<i>isUnique</i>" * default="<i>defaultValue</i>" * foreignKey="<i>foreignTableName.columnName onDeleteAction</i>"/> * </table> * </database> * </pre> * * About the attributes: * <ul> * <li> <b>tableName</b> - The desired name of the table. * <li> <b>primaryColumnName</b> - Identifies column that is the primary * key for the table. A column that is a primary key must be notNull, and * can't be a foreign key. * <li> <b>type</b> - The table type, which is RDBMS-specific. See * TableSpec(String, Set, String, String) for detail. * <li> <b>columnName</b> - The name of the column. * <li> <b>typeSpec</b> - The value type of the column. For instance, * varchar(255). This is not checked for validity. See <a * href="ColumnSpec.html">ColumnSpec javadoc</a> for detail. * <li> <b>isAutoIncremented</b> - (true|false) Whether values in the * column should be automatically generated by the database upon insert. * This requires that the type be some numeric variant, and is * RDBMS-specific. NUMERIC will generally work. * <li> <b>indexName</b> - Specifies that an index should be created on * this column and provides the column name. * <li> <b>isNotNull</b> - (true|false) Whether input should be limited to * actual values. * <li> <b>isUnique</b> - (true|false) Whether input should be limited such * that all values in the column are unique. * <li> <b>default</b> - The value to be used when inserts don't specify a * value for the column. This cannot be specified with autoIncrement true. * <li> <b>foreignTableName.column</b> - Specifies that this is a foreign * key column and identifies the (primary key) column in the database * containing the rows that values in this column refer to. This cannot be * specified with autoIncrement true. * <li> <b>onDeleteAction</b> - Optionally specifies a "CASCADE" or "SET * NULL" action to be taken on matching rows in this table when a row from * the parent (foreign) table is deleted. If "CASCADE", matching rows in * this table are automatically deleted. If "SET NULL", this column's value * will be set to NULL for all matching rows. This value is not checked for * validity. * </ul> * * @param in * The xml-encoded table specs. * @return TableSpec objects. * @throws InconsistentTableSpecException * if inconsistencies are detected in table specifications. * @throws IOException * if an IO error occurs. */ public static List<TableSpec> getTableSpecs(InputStream in) throws InconsistentTableSpecException, IOException { try { SAXParserFactory spf = SAXParserFactory.newInstance(); spf.setNamespaceAware(true); SAXParser parser = spf.newSAXParser(); TableSpecDeserializer tsd = new TableSpecDeserializer(); parser.parse(in, tsd); tsd.assertTableSpecsConsistent(); return tsd.getTableSpecs(); } catch (InconsistentTableSpecException itse) { throw itse; } catch (Exception e) { throw new IOException("Error parsing XML: " + e.getMessage()); } } /** * Ensures that the TableSpec is internally consistent. * * @throws InconsistentTableSpecException * If it's inconsistent. */ public void assertConsistent() throws InconsistentTableSpecException { if (1 == 2) { throw new InconsistentTableSpecException("hmm"); } } /** * Gets the name of the table. * * @return The name. */ public String getName() { return m_name; } /** * Gets the name of the primary key column. * * @return The name. */ public String getPrimaryColumnName() { return m_primaryColumnName; } /** * Gets the type of the table. * * @return The name. */ public String getType() { return m_type; } /** * Gets an iterator over the columns. * * @return An Iterator over ColumnSpec objects. */ public Iterator<ColumnSpec> columnSpecIterator() { return m_columnSpecs.iterator(); } }