All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.torque.engine.database.model.Table Maven / Gradle / Ivy

package org.apache.torque.engine.database.model;

/*
 * 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.util.ArrayList;
import java.util.Collections;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.collections.map.ListOrderedMap;
import org.apache.commons.lang.StringUtils;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.torque.engine.EngineException;

import org.xml.sax.Attributes;

/**
 * Data about a table used in an application.
 * 
 * @author Leon Messerschmidt
 * @author Jason van Zyl
 * @author John McNally
 * @author Byron Foster
 * @author 
	 * A hook for the SAX XML parser to call when this table has been fully loaded from the XML, and all nested elements
	 * have been processed.
	 * 

* *

* Performs heavy indexing and naming of elements which weren't provided with a name. *

*/ public void doFinalInitialization() { // Heavy indexing must wait until after all columns composing // a table's primary key have been parsed. if (heavyIndexing) { doHeavyIndexing(); } // Name any indices which are missing a name using the // appropriate algorithm. doNaming(); } /** *

* Adds extra indices for multi-part primary key columns. *

* *

* For databases like MySQL, values in a where clause must match key part order from the left to right. So, in the * key definition PRIMARY KEY (FOO_ID, BAR_ID), FOO_ID must be the first element * used in the where clause of the SQL query used against this table for the primary key index to be * used. This feature could cause problems under MySQL with heavily indexed tables, as MySQL currently only supports * 16 indices per table (i.e. it might cause too many indices to be created). *

* *

* See the manual for a better description of why heavy * indexing is useful for quickly searchable database tables. *

*/ private void doHeavyIndexing() { if (log.isDebugEnabled()) { log.debug("doHeavyIndex() called on table " + name); } List pk = getPrimaryKey(); int size = pk.size(); try { // We start at an offset of 1 because the entire column // list is generally implicitly indexed by the fact that // it's a primary key. for (int i = 1; i < size; i++) { addIndex(new Index(this, pk.subList(i, size))); } } catch (EngineException e) { log.error(e, e); } } /** * Names composing objects which haven't yet been named. This currently consists of foreign-key and index entities. */ private void doNaming() { int i; int size; String name; // Assure names are unique across all databases. try { for (i = 0, size = foreignKeys.size(); i < size; i++) { ForeignKey fk = (ForeignKey) foreignKeys.get(i); name = fk.getName(); if (StringUtils.isEmpty(name)) { name = acquireConstraintName("FK", i + 1); fk.setName(name); } } for (i = 0, size = indices.size(); i < size; i++) { Index index = (Index) indices.get(i); name = index.getName(); if (StringUtils.isEmpty(name)) { name = acquireConstraintName("I", i + 1); index.setName(name); } } for (i = 0, size = unices.size(); i < size; i++) { Unique unique = (Unique) unices.get(i); name = unique.getName(); if (StringUtils.isEmpty(name)) { name = acquireConstraintName("U", i + 1); unique.setName(name); } } } catch (EngineException nameAlreadyInUse) { log.error(nameAlreadyInUse, nameAlreadyInUse); } } /** * Macro to a constraint name. * * @param nameType * constraint type * @param nbr * unique number for this constraint type * @return unique name for constraint * @throws EngineException */ private final String acquireConstraintName(String nameType, int nbr) throws EngineException { List inputs = new ArrayList(4); inputs.add(getDatabase()); inputs.add(getName()); inputs.add(nameType); inputs.add(new Integer(nbr)); return NameFactory.generateName(NameFactory.CONSTRAINT_GENERATOR, inputs); } /** * Gets the value of base class for classes produced from this table. * * @return The base class for classes produced from this table. */ public String getBaseClass() { if (isAlias() && baseClass == null) { return alias; } else if (baseClass == null) { return getDatabase().getBaseClass(); } else { return baseClass; } } /** * Set the value of baseClass. * * @param v * Value to assign to baseClass. */ public void setBaseClass(String v) { this.baseClass = v; } /** * Get the value of basePeer. * * @return value of basePeer. */ public String getBasePeer() { if (isAlias() && basePeer == null) { return alias + "Peer"; } else if (basePeer == null) { return getDatabase().getBasePeer(); } else { return basePeer; } } /** * Set the value of basePeer. * * @param v * Value to assign to basePeer. */ public void setBasePeer(String v) { this.basePeer = v; } /** * A utility function to create a new column from attrib and add it to this table. * * @param attrib * xml attributes for the column to add * @return the added column */ public Column addColumn(Attributes attrib) { Column col = new Column(); col.setTable(this); col.setCorrectGetters(false); col.loadFromXML(attrib); addColumn(col); return col; } /** * Adds a new column to the column list and set the parent table of the column to the current table * * @param col * the column to add */ public void addColumn(Column col) { col.setTable(this); if (col.isInheritance()) { inheritanceColumn = col; } columnList.add(col); columnsByName.put(col.getName(), col); columnsByJavaName.put(col.getJavaName(), col); col.setPosition(columnList.size()); needsTransactionInPostgres |= col.requiresTransactionInPostgres(); } /** * A utility function to create a new foreign key from attrib and add it to this table. * * @param attrib * the xml attributes * @return the created ForeignKey */ public ForeignKey addForeignKey(Attributes attrib) { ForeignKey fk = new ForeignKey(); fk.loadFromXML(attrib); addForeignKey(fk); return fk; } /** * Gets the column that subclasses of the class representing this table can be produced from. */ public Column getChildrenColumn() { return inheritanceColumn; } /** * Get the objects that can be created from this table. */ public List getChildrenNames() { if (inheritanceColumn == null || !inheritanceColumn.isEnumeratedClasses()) { return null; } List children = inheritanceColumn.getChildren(); List names = new ArrayList(children.size()); for (int i = 0; i < children.size(); i++) { names.add(((Inheritance) children.get(i)).getClassName()); } return names; } /** * Adds the foreign key from another table that refers to this table. * * @param fk * A foreign key refering to this table */ public void addReferrer(ForeignKey fk) { if (referrers == null) { referrers = new ArrayList(5); } referrers.add(fk); } /** * Get list of references to this table. * * @return A list of references to this table */ public List getReferrers() { return referrers; } /** * Set whether this table contains a foreign PK * * @param b */ public void setContainsForeignPK(boolean b) { containsForeignPK = b; } /** * Determine if this table contains a foreign PK */ public boolean getContainsForeignPK() { return containsForeignPK; } /** * A list of tables referenced by foreign keys in this table * * @return A list of tables */ public List getForeignTableNames() { if (foreignTableNames == null) { foreignTableNames = new ArrayList(1); } return foreignTableNames; } /** * Adds a new FK to the FK list and set the parent table of the column to the current table * * @param fk * A foreign key */ public void addForeignKey(ForeignKey fk) { fk.setTable(this); foreignKeys.add(fk); if (foreignTableNames == null) { foreignTableNames = new ArrayList(5); } if (!foreignTableNames.contains(fk.getForeignTableName())) { foreignTableNames.add(fk.getForeignTableName()); } } /** * Return true if the column requires a transaction in Postgres */ public boolean requiresTransactionInPostgres() { return needsTransactionInPostgres; } /** * A utility function to create a new id method parameter from attrib and add it to this table. */ public IdMethodParameter addIdMethodParameter(Attributes attrib) { IdMethodParameter imp = new IdMethodParameter(); imp.loadFromXML(attrib); addIdMethodParameter(imp); return imp; } /** * Adds a new ID method parameter to the list and sets the parent table of the column associated with the supplied * parameter to this table. * * @param imp * The column to add as an ID method parameter. */ public void addIdMethodParameter(IdMethodParameter imp) { imp.setTable(this); if (idMethodParameters == null) { idMethodParameters = new ArrayList(2); } idMethodParameters.add(imp); } /** * Adds a new index to the index list and set the parent table of the column to the current table */ public void addIndex(Index index) { index.setTable(this); indices.add(index); } /** * A utility function to create a new index from attrib and add it to this table. */ public Index addIndex(Attributes attrib) { Index index = new Index(); index.loadFromXML(attrib); addIndex(index); return index; } /** * Adds a new Unique to the Unique list and set the parent table of the column to the current table */ public void addUnique(Unique unique) { unique.setTable(this); unices.add(unique); } /** * A utility function to create a new Unique from attrib and add it to this table. * * @param attrib * the xml attributes */ public Unique addUnique(Attributes attrib) { Unique unique = new Unique(); unique.loadFromXML(attrib); addUnique(unique); return unique; } /** * Get the name of the Table */ public String getName() { return name; } /** * Set the name of the Table */ public void setName(String newName) { name = newName; } /** * Get the description for the Table */ public String getDescription() { return description; } /** * Set the description for the Table * * @param newDescription * description for the Table */ public void setDescription(String newDescription) { description = newDescription; } /** * Get name to use in Java sources */ public String getJavaName() { if (javaName == null) { List inputs = new ArrayList(2); inputs.add(name); inputs.add(javaNamingMethod); try { javaName = NameFactory.generateName(NameFactory.JAVA_GENERATOR, inputs); } catch (EngineException e) { log.error(e, e); } } return javaName; } /** * Set name to use in Java sources */ public void setJavaName(String javaName) { this.javaName = javaName; } /** * Get the method for generating pk's */ public String getIdMethod() { if (idMethod == null) { return IDMethod.NO_ID_METHOD; } else { return idMethod; } } /** * Set the method for generating pk's */ public void setIdMethod(String idMethod) { this.idMethod = idMethod; } /** * Skip generating sql for this table (in the event it should not be created from scratch). * * @return value of skipSql. */ public boolean isSkipSql() { return (skipSql || isAlias() || isForReferenceOnly()); } /** * Set whether this table should have its creation sql generated. * * @param v * Value to assign to skipSql. */ public void setSkipSql(boolean v) { this.skipSql = v; } /** * JavaName of om object this entry references. * * @return value of external. */ public String getAlias() { return alias; } /** * Is this table specified in the schema or is there just a foreign key reference to it. * * @return value of external. */ public boolean isAlias() { return (alias != null); } /** * Set whether this table specified in the schema or is there just a foreign key reference to it. * * @param v * Value to assign to alias. */ public void setAlias(String v) { this.alias = v; } /** * Interface which objects for this table will implement * * @return value of interface. */ public String getInterface() { return enterface; } /** * Interface which objects for this table will implement * * @param v * Value to assign to interface. */ public void setInterface(String v) { this.enterface = v; } /** * When a table is abstract, it marks the business object class that is generated as being abstract. If you have a * table called "FOO", then the Foo BO will be public abstract class Foo This helps support class * hierarchies * * @return value of abstractValue. */ public boolean isAbstract() { return abstractValue; } /** * When a table is abstract, it marks the business object class that is generated as being abstract. If you have a * table called "FOO", then the Foo BO will be public abstract class Foo This helps support class * hierarchies * * @param v * Value to assign to abstractValue. */ public void setAbstract(boolean v) { this.abstractValue = v; } /** * Get the value of package. * * @return value of package. */ public String getPackage() { if (pkg != null) { return pkg; } else { return this.getDatabase().getPackage(); } } /** * Set the value of package. * * @param v * Value to assign to package. */ public void setPackage(String v) { this.pkg = v; } /** * Returns a List containing all the columns in the table * * @return a List containing all the columns */ public List getColumns() { return columnList; } /** * Utility method to get the number of columns in this table */ public int getNumColumns() { return columnList.size(); } /** * Returns a List containing all the FKs in the table * * @return a List containing all the FKs */ public List getForeignKeys() { return foreignKeys; } /** * Returns a Collection of parameters relevant for the chosen id generation method. */ public List getIdMethodParameters() { return idMethodParameters; } /** * A name to use for creating a sequence if one is not specified. * * @return name of the sequence */ public String getSequenceName() { String result = null; if (getIdMethod().equals(NATIVE)) { List idMethodParams = getIdMethodParameters(); if (idMethodParams == null) { result = getName() + "_SEQ"; } else { result = ((IdMethodParameter) idMethodParams.get(0)).getValue(); } } return result; } /** * Returns a List containing all the indices in the table * * @return A List containing all the indices */ public List getIndices() { return indices; } /** * Returns a List containing all the UKs in the table * * @return A List containing all the UKs */ public List getUnices() { return unices; } /** * Returns a specified column. * * @param name * name of the column * @return Return a Column object or null if it does not exist. */ public Column getColumn(String name) { return (Column) columnsByName.get(name); } /** * Returns a specified column. * * @param javaName * java name of the column * @return Return a Column object or null if it does not exist. */ public Column getColumnByJavaName(String javaName) { return (Column) columnsByJavaName.get(javaName); } /** * Return the first foreign key that includes col in it's list of local columns. Eg. Foreign key (a,b,c) refrences * tbl(x,y,z) will be returned of col is either a,b or c. * * @param col * column name included in the key * @return Return a Column object or null if it does not exist. */ public ForeignKey getForeignKey(String col) { ForeignKey firstFK = null; for (Iterator iter = foreignKeys.iterator(); iter.hasNext();) { ForeignKey key = (ForeignKey) iter.next(); if (key.getLocalColumns().contains(col)) { if (firstFK == null) { firstFK = key; } else { // System.out.println(col+" is in multiple FKs. This is not" // + " being handled properly."); // throw new IllegalStateException("Cannot call method if " + // "column is referenced multiple times"); } } } return firstFK; } /** * Returns true if the table contains a specified column * * @param col * the column * @return true if the table contains the column */ public boolean containsColumn(Column col) { return columnList.contains(col); } /** * Returns true if the table contains a specified column * * @param name * name of the column * @return true if the table contains the column */ public boolean containsColumn(String name) { return (getColumn(name) != null); } /** * Set the parent of the table * * @param parent * the parant database */ public void setDatabase(Database parent) { tableParent = parent; } /** * Get the parent of the table * * @return the parant database */ public Database getDatabase() { return tableParent; } /** * Flag to determine if code/sql gets created for this table. Table will be skipped, if return true. * * @return value of forReferenceOnly. */ public boolean isForReferenceOnly() { return forReferenceOnly; } /** * Flag to determine if code/sql gets created for this table. Table will be skipped, if set to true. * * @param v * Value to assign to forReferenceOnly. */ public void setForReferenceOnly(boolean v) { this.forReferenceOnly = v; } /** * Returns a XML representation of this table. * * @return XML representation of this table */ public String toString() { StringBuffer result = new StringBuffer(); result.append("\n"); if (columnList != null) { for (Iterator iter = columnList.iterator(); iter.hasNext();) { result.append(iter.next()); } } if (foreignKeys != null) { for (Iterator iter = foreignKeys.iterator(); iter.hasNext();) { result.append(iter.next()); } } if (idMethodParameters != null) { Iterator iter = idMethodParameters.iterator(); while (iter.hasNext()) { result.append(iter.next()); } } result.append("
\n"); return result.toString(); } /** * Returns the collection of Columns which make up the single primary key for this table. * * @return A list of the primary key parts. */ public List getPrimaryKey() { List pk = new ArrayList(columnList.size()); Iterator iter = columnList.iterator(); while (iter.hasNext()) { Column col = (Column) iter.next(); if (col.isPrimaryKey()) { pk.add(col); } } return pk; } /** * Determine whether this table has a primary key. * * @return Whether this table has any primary key parts. */ public boolean hasPrimaryKey() { return (getPrimaryKey().size() > 0); } /** * Returns all parts of the primary key, separated by commas. * * @return A CSV list of primary key parts. */ public String printPrimaryKey() { return printList(columnList); } /** * Returns the elements of the list, separated by commas. * * @param list * a list of Columns * @return A CSV list. */ private String printList(List list) { StringBuffer result = new StringBuffer(); boolean comma = false; for (Iterator iter = list.iterator(); iter.hasNext();) { Column col = (Column) iter.next(); if (col.isPrimaryKey()) { if (comma) { result.append(','); } else { comma = true; } result.append(col.getName()); } } return result.toString(); } /** * Force all columns to set the correctGetters property. * * @param value * The new value of the correctGetters property. * @since 3.2 */ public void setCorrectGetters(Boolean value) { boolean correctGetters = value != null && value.booleanValue(); for (Iterator it = columnList.iterator(); it.hasNext();) { Column col = (Column) it.next(); col.setCorrectGetters(correctGetters); } } /** * Add an XML Specified option key/value pair to this element's option set. * * @param key * the key of the option. * @param value * the value of the option. */ public void addOption(String key, String value) { options.put(key, value); } /** * Get the value that was associated with this key in an XML option element. * * @param key * the key of the option. * @return The value for the key or a null. */ public String getOption(String key) { return (String) options.get(key); } /** * Gets the full ordered hashtable array of items specified by XML option statements under this element. *

* * Note, this is not thread save but since it's only used for generation which is single threaded, there should be * minimum danger using this in Velocity. * * @return An Map of all options. Will not be null but may be empty. */ public Map getOptions() { return options; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy