Clover Coverage Report - Impex Parent 1.0.21-SNAPSHOT (Aggregated)
Coverage timestamp: Tue Feb 8 2011 11:33:53 EST
../../../../../../img/srcFileCovDistChart0.png 0% of files have more coverage
250   1,052   128   3.42
98   500   0.51   73
73     1.75  
1    
 
  Table       Line # 50 250 0% 128 421 0% 0.0
 
No Tests
 
1    package org.apache.torque.engine.database.model;
2   
3    /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements. See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership. The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10    * with the License. You may obtain a copy of the License at
11    *
12    * http://www.apache.org/licenses/LICENSE-2.0
13    *
14    * Unless required by applicable law or agreed to in writing,
15    * software distributed under the License is distributed on an
16    * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17    * KIND, either express or implied. See the License for the
18    * specific language governing permissions and limitations
19    * under the License.
20    */
21   
22    import java.util.ArrayList;
23    import java.util.Collections;
24    import java.util.Hashtable;
25    import java.util.Iterator;
26    import java.util.List;
27    import java.util.Map;
28    import org.apache.commons.collections.map.ListOrderedMap;
29    import org.apache.commons.lang.StringUtils;
30   
31    import org.apache.commons.logging.Log;
32    import org.apache.commons.logging.LogFactory;
33   
34    import org.apache.torque.engine.EngineException;
35   
36    import org.xml.sax.Attributes;
37   
38    /**
39    * Data about a table used in an application.
40    *
41    * @author <a href="mailto:leon@opticode.co.za">Leon Messerschmidt</a>
42    * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
43    * @author <a href="mailto:mpoeschl@marmot.at>Martin Poeschl</a>
44    * @author <a href="mailto:jmcnally@collab.net>John McNally</a>
45    * @author <a href="mailto:dlr@collab.net>Daniel Rall</a>
46    * @author <a href="mailto:byron_foster@byron_foster@yahoo.com>Byron Foster</a>
47    * @author <a href="mailto:monroe@dukece.com>Greg Monroe</a>
48    * @version $Id: Table.java,v 1.1 2007-10-21 07:57:27 abyrne Exp $
49    */
 
50    public class Table implements IDMethod {
51    /** Logging class from commons.logging */
52    private static Log log = LogFactory.getLog(Table.class);
53   
54    // private AttributeListImpl attributes;
55    private List columnList;
56    private List foreignKeys;
57    private List indices;
58    private List unices;
59    private List idMethodParameters;
60    private String name;
61    private String description;
62    private String javaName;
63    private String idMethod;
64    private String javaNamingMethod;
65    private Database tableParent;
66    private List referrers;
67    private List foreignTableNames;
68    private boolean containsForeignPK;
69    private Column inheritanceColumn;
70    private boolean skipSql;
71    private boolean abstractValue;
72    private String alias;
73    private String enterface;
74    private String pkg;
75    private String baseClass;
76    private String basePeer;
77    private Hashtable columnsByName;
78    private Hashtable columnsByJavaName;
79    private boolean needsTransactionInPostgres;
80    private boolean heavyIndexing;
81    private boolean forReferenceOnly;
82    private Map options;
83   
84    /**
85    * Default Constructor
86    */
 
87  0 toggle public Table() {
88  0 this(null);
89    }
90   
91    /**
92    * Constructs a table object with a name
93    *
94    * @param name
95    * table name
96    */
 
97  0 toggle public Table(String name) {
98  0 this.name = name;
99  0 columnList = new ArrayList();
100  0 foreignKeys = new ArrayList(5);
101  0 indices = new ArrayList(5);
102  0 unices = new ArrayList(5);
103  0 columnsByName = new Hashtable();
104  0 columnsByJavaName = new Hashtable();
105  0 options = Collections.synchronizedMap(new ListOrderedMap());
106    }
107   
108    /**
109    * Load the table object from an xml tag.
110    *
111    * @param attrib
112    * xml attributes
113    * @param defaultIdMethod
114    * defined at db level
115    */
 
116  0 toggle public void loadFromXML(Attributes attrib, String defaultIdMethod) {
117  0 name = attrib.getValue("name");
118  0 javaName = attrib.getValue("javaName");
119  0 idMethod = attrib.getValue("idMethod");
120   
121    // retrieves the method for converting from specified name to
122    // a java name.
123  0 javaNamingMethod = attrib.getValue("javaNamingMethod");
124  0 if (javaNamingMethod == null) {
125  0 javaNamingMethod = getDatabase().getDefaultJavaNamingMethod();
126    }
127   
128  0 if ("null".equals(idMethod)) {
129  0 idMethod = defaultIdMethod;
130    }
131  0 skipSql = "true".equals(attrib.getValue("skipSql"));
132    // pkg = attrib.getValue("package");
133  0 abstractValue = "true".equals(attrib.getValue("abstract"));
134  0 baseClass = attrib.getValue("baseClass");
135  0 basePeer = attrib.getValue("basePeer");
136  0 alias = attrib.getValue("alias");
137  0 heavyIndexing = "true".equals(attrib.getValue("heavyIndexing")) || (!"false".equals(attrib.getValue("heavyIndexing")) && getDatabase().isHeavyIndexing());
138  0 description = attrib.getValue("description");
139  0 enterface = attrib.getValue("interface");
140    }
141   
142    /**
143    * <p>
144    * A hook for the SAX XML parser to call when this table has been fully loaded from the XML, and all nested elements
145    * have been processed.
146    * </p>
147    *
148    * <p>
149    * Performs heavy indexing and naming of elements which weren't provided with a name.
150    * </p>
151    */
 
152  0 toggle public void doFinalInitialization() {
153    // Heavy indexing must wait until after all columns composing
154    // a table's primary key have been parsed.
155  0 if (heavyIndexing) {
156  0 doHeavyIndexing();
157    }
158   
159    // Name any indices which are missing a name using the
160    // appropriate algorithm.
161  0 doNaming();
162    }
163   
164    /**
165    * <p>
166    * Adds extra indices for multi-part primary key columns.
167    * </p>
168    *
169    * <p>
170    * For databases like MySQL, values in a where clause must match key part order from the left to right. So, in the
171    * key definition <code>PRIMARY KEY (FOO_ID, BAR_ID)</code>, <code>FOO_ID</code> <i>must</i> be the first element
172    * used in the <code>where</code> clause of the SQL query used against this table for the primary key index to be
173    * used. This feature could cause problems under MySQL with heavily indexed tables, as MySQL currently only supports
174    * 16 indices per table (i.e. it might cause too many indices to be created).
175    * </p>
176    *
177    * <p>
178    * See <a href="http://www.mysql.com/doc/E/X/EXPLAIN.html">the manual</a> for a better description of why heavy
179    * indexing is useful for quickly searchable database tables.
180    * </p>
181    */
 
182  0 toggle private void doHeavyIndexing() {
183  0 if (log.isDebugEnabled()) {
184  0 log.debug("doHeavyIndex() called on table " + name);
185    }
186   
187  0 List pk = getPrimaryKey();
188  0 int size = pk.size();
189   
190  0 try {
191    // We start at an offset of 1 because the entire column
192    // list is generally implicitly indexed by the fact that
193    // it's a primary key.
194  0 for (int i = 1; i < size; i++) {
195  0 addIndex(new Index(this, pk.subList(i, size)));
196    }
197    } catch (EngineException e) {
198  0 log.error(e, e);
199    }
200    }
201   
202    /**
203    * Names composing objects which haven't yet been named. This currently consists of foreign-key and index entities.
204    */
 
205  0 toggle private void doNaming() {
206  0 int i;
207  0 int size;
208  0 String name;
209   
210    // Assure names are unique across all databases.
211  0 try {
212  0 for (i = 0, size = foreignKeys.size(); i < size; i++) {
213  0 ForeignKey fk = (ForeignKey) foreignKeys.get(i);
214  0 name = fk.getName();
215  0 if (StringUtils.isEmpty(name)) {
216  0 name = acquireConstraintName("FK", i + 1);
217  0 fk.setName(name);
218    }
219    }
220   
221  0 for (i = 0, size = indices.size(); i < size; i++) {
222  0 Index index = (Index) indices.get(i);
223  0 name = index.getName();
224  0 if (StringUtils.isEmpty(name)) {
225  0 name = acquireConstraintName("I", i + 1);
226  0 index.setName(name);
227    }
228    }
229   
230  0 for (i = 0, size = unices.size(); i < size; i++) {
231  0 Unique unique = (Unique) unices.get(i);
232  0 name = unique.getName();
233  0 if (StringUtils.isEmpty(name)) {
234  0 name = acquireConstraintName("U", i + 1);
235  0 unique.setName(name);
236    }
237    }
238    } catch (EngineException nameAlreadyInUse) {
239  0 log.error(nameAlreadyInUse, nameAlreadyInUse);
240    }
241    }
242   
243    /**
244    * Macro to a constraint name.
245    *
246    * @param nameType
247    * constraint type
248    * @param nbr
249    * unique number for this constraint type
250    * @return unique name for constraint
251    * @throws EngineException
252    */
 
253  0 toggle private final String acquireConstraintName(String nameType, int nbr) throws EngineException {
254  0 List inputs = new ArrayList(4);
255  0 inputs.add(getDatabase());
256  0 inputs.add(getName());
257  0 inputs.add(nameType);
258  0 inputs.add(new Integer(nbr));
259  0 return NameFactory.generateName(NameFactory.CONSTRAINT_GENERATOR, inputs);
260    }
261   
262    /**
263    * Gets the value of base class for classes produced from this table.
264    *
265    * @return The base class for classes produced from this table.
266    */
 
267  0 toggle public String getBaseClass() {
268  0 if (isAlias() && baseClass == null) {
269  0 return alias;
270  0 } else if (baseClass == null) {
271  0 return getDatabase().getBaseClass();
272    } else {
273  0 return baseClass;
274    }
275    }
276   
277    /**
278    * Set the value of baseClass.
279    *
280    * @param v
281    * Value to assign to baseClass.
282    */
 
283  0 toggle public void setBaseClass(String v) {
284  0 this.baseClass = v;
285    }
286   
287    /**
288    * Get the value of basePeer.
289    *
290    * @return value of basePeer.
291    */
 
292  0 toggle public String getBasePeer() {
293  0 if (isAlias() && basePeer == null) {
294  0 return alias + "Peer";
295  0 } else if (basePeer == null) {
296  0 return getDatabase().getBasePeer();
297    } else {
298  0 return basePeer;
299    }
300    }
301   
302    /**
303    * Set the value of basePeer.
304    *
305    * @param v
306    * Value to assign to basePeer.
307    */
 
308  0 toggle public void setBasePeer(String v) {
309  0 this.basePeer = v;
310    }
311   
312    /**
313    * A utility function to create a new column from attrib and add it to this table.
314    *
315    * @param attrib
316    * xml attributes for the column to add
317    * @return the added column
318    */
 
319  0 toggle public Column addColumn(Attributes attrib) {
320  0 Column col = new Column();
321  0 col.setTable(this);
322  0 col.setCorrectGetters(false);
323  0 col.loadFromXML(attrib);
324  0 addColumn(col);
325  0 return col;
326    }
327   
328    /**
329    * Adds a new column to the column list and set the parent table of the column to the current table
330    *
331    * @param col
332    * the column to add
333    */
 
334  0 toggle public void addColumn(Column col) {
335  0 col.setTable(this);
336  0 if (col.isInheritance()) {
337  0 inheritanceColumn = col;
338    }
339  0 columnList.add(col);
340  0 columnsByName.put(col.getName(), col);
341  0 columnsByJavaName.put(col.getJavaName(), col);
342  0 col.setPosition(columnList.size());
343  0 needsTransactionInPostgres |= col.requiresTransactionInPostgres();
344    }
345   
346    /**
347    * A utility function to create a new foreign key from attrib and add it to this table.
348    *
349    * @param attrib
350    * the xml attributes
351    * @return the created ForeignKey
352    */
 
353  0 toggle public ForeignKey addForeignKey(Attributes attrib) {
354  0 ForeignKey fk = new ForeignKey();
355  0 fk.loadFromXML(attrib);
356  0 addForeignKey(fk);
357  0 return fk;
358    }
359   
360    /**
361    * Gets the column that subclasses of the class representing this table can be produced from.
362    */
 
363  0 toggle public Column getChildrenColumn() {
364  0 return inheritanceColumn;
365    }
366   
367    /**
368    * Get the objects that can be created from this table.
369    */
 
370  0 toggle public List getChildrenNames() {
371  0 if (inheritanceColumn == null || !inheritanceColumn.isEnumeratedClasses()) {
372  0 return null;
373    }
374  0 List children = inheritanceColumn.getChildren();
375  0 List names = new ArrayList(children.size());
376  0 for (int i = 0; i < children.size(); i++) {
377  0 names.add(((Inheritance) children.get(i)).getClassName());
378    }
379  0 return names;
380    }
381   
382    /**
383    * Adds the foreign key from another table that refers to this table.
384    *
385    * @param fk
386    * A foreign key refering to this table
387    */
 
388  0 toggle public void addReferrer(ForeignKey fk) {
389  0 if (referrers == null) {
390  0 referrers = new ArrayList(5);
391    }
392  0 referrers.add(fk);
393    }
394   
395    /**
396    * Get list of references to this table.
397    *
398    * @return A list of references to this table
399    */
 
400  0 toggle public List getReferrers() {
401  0 return referrers;
402    }
403   
404    /**
405    * Set whether this table contains a foreign PK
406    *
407    * @param b
408    */
 
409  0 toggle public void setContainsForeignPK(boolean b) {
410  0 containsForeignPK = b;
411    }
412   
413    /**
414    * Determine if this table contains a foreign PK
415    */
 
416  0 toggle public boolean getContainsForeignPK() {
417  0 return containsForeignPK;
418    }
419   
420    /**
421    * A list of tables referenced by foreign keys in this table
422    *
423    * @return A list of tables
424    */
 
425  0 toggle public List getForeignTableNames() {
426  0 if (foreignTableNames == null) {
427  0 foreignTableNames = new ArrayList(1);
428    }
429  0 return foreignTableNames;
430    }
431   
432    /**
433    * Adds a new FK to the FK list and set the parent table of the column to the current table
434    *
435    * @param fk
436    * A foreign key
437    */
 
438  0 toggle public void addForeignKey(ForeignKey fk) {
439  0 fk.setTable(this);
440  0 foreignKeys.add(fk);
441   
442  0 if (foreignTableNames == null) {
443  0 foreignTableNames = new ArrayList(5);
444    }
445  0 if (!foreignTableNames.contains(fk.getForeignTableName())) {
446  0 foreignTableNames.add(fk.getForeignTableName());
447    }
448    }
449   
450    /**
451    * Return true if the column requires a transaction in Postgres
452    */
 
453  0 toggle public boolean requiresTransactionInPostgres() {
454  0 return needsTransactionInPostgres;
455    }
456   
457    /**
458    * A utility function to create a new id method parameter from attrib and add it to this table.
459    */
 
460  0 toggle public IdMethodParameter addIdMethodParameter(Attributes attrib) {
461  0 IdMethodParameter imp = new IdMethodParameter();
462  0 imp.loadFromXML(attrib);
463  0 addIdMethodParameter(imp);
464  0 return imp;
465    }
466   
467    /**
468    * Adds a new ID method parameter to the list and sets the parent table of the column associated with the supplied
469    * parameter to this table.
470    *
471    * @param imp
472    * The column to add as an ID method parameter.
473    */
 
474  0 toggle public void addIdMethodParameter(IdMethodParameter imp) {
475  0 imp.setTable(this);
476  0 if (idMethodParameters == null) {
477  0 idMethodParameters = new ArrayList(2);
478    }
479  0 idMethodParameters.add(imp);
480    }
481   
482    /**
483    * Adds a new index to the index list and set the parent table of the column to the current table
484    */
 
485  0 toggle public void addIndex(Index index) {
486  0 index.setTable(this);
487  0 indices.add(index);
488    }
489   
490    /**
491    * A utility function to create a new index from attrib and add it to this table.
492    */
 
493  0 toggle public Index addIndex(Attributes attrib) {
494  0 Index index = new Index();
495  0 index.loadFromXML(attrib);
496  0 addIndex(index);
497  0 return index;
498    }
499   
500    /**
501    * Adds a new Unique to the Unique list and set the parent table of the column to the current table
502    */
 
503  0 toggle public void addUnique(Unique unique) {
504  0 unique.setTable(this);
505  0 unices.add(unique);
506    }
507   
508    /**
509    * A utility function to create a new Unique from attrib and add it to this table.
510    *
511    * @param attrib
512    * the xml attributes
513    */
 
514  0 toggle public Unique addUnique(Attributes attrib) {
515  0 Unique unique = new Unique();
516  0 unique.loadFromXML(attrib);
517  0 addUnique(unique);
518  0 return unique;
519    }
520   
521    /**
522    * Get the name of the Table
523    */
 
524  0 toggle public String getName() {
525  0 return name;
526    }
527   
528    /**
529    * Set the name of the Table
530    */
 
531  0 toggle public void setName(String newName) {
532  0 name = newName;
533    }
534   
535    /**
536    * Get the description for the Table
537    */
 
538  0 toggle public String getDescription() {
539  0 return description;
540    }
541   
542    /**
543    * Set the description for the Table
544    *
545    * @param newDescription
546    * description for the Table
547    */
 
548  0 toggle public void setDescription(String newDescription) {
549  0 description = newDescription;
550    }
551   
552    /**
553    * Get name to use in Java sources
554    */
 
555  0 toggle public String getJavaName() {
556  0 if (javaName == null) {
557  0 List inputs = new ArrayList(2);
558  0 inputs.add(name);
559  0 inputs.add(javaNamingMethod);
560  0 try {
561  0 javaName = NameFactory.generateName(NameFactory.JAVA_GENERATOR, inputs);
562    } catch (EngineException e) {
563  0 log.error(e, e);
564    }
565    }
566  0 return javaName;
567    }
568   
569    /**
570    * Set name to use in Java sources
571    */
 
572  0 toggle public void setJavaName(String javaName) {
573  0 this.javaName = javaName;
574    }
575   
576    /**
577    * Get the method for generating pk's
578    */
 
579  0 toggle public String getIdMethod() {
580  0 if (idMethod == null) {
581  0 return IDMethod.NO_ID_METHOD;
582    } else {
583  0 return idMethod;
584    }
585    }
586   
587    /**
588    * Set the method for generating pk's
589    */
 
590  0 toggle public void setIdMethod(String idMethod) {
591  0 this.idMethod = idMethod;
592    }
593   
594    /**
595    * Skip generating sql for this table (in the event it should not be created from scratch).
596    *
597    * @return value of skipSql.
598    */
 
599  0 toggle public boolean isSkipSql() {
600  0 return (skipSql || isAlias() || isForReferenceOnly());
601    }
602   
603    /**
604    * Set whether this table should have its creation sql generated.
605    *
606    * @param v
607    * Value to assign to skipSql.
608    */
 
609  0 toggle public void setSkipSql(boolean v) {
610  0 this.skipSql = v;
611    }
612   
613    /**
614    * JavaName of om object this entry references.
615    *
616    * @return value of external.
617    */
 
618  0 toggle public String getAlias() {
619  0 return alias;
620    }
621   
622    /**
623    * Is this table specified in the schema or is there just a foreign key reference to it.
624    *
625    * @return value of external.
626    */
 
627  0 toggle public boolean isAlias() {
628  0 return (alias != null);
629    }
630   
631    /**
632    * Set whether this table specified in the schema or is there just a foreign key reference to it.
633    *
634    * @param v
635    * Value to assign to alias.
636    */
 
637  0 toggle public void setAlias(String v) {
638  0 this.alias = v;
639    }
640   
641    /**
642    * Interface which objects for this table will implement
643    *
644    * @return value of interface.
645    */
 
646  0 toggle public String getInterface() {
647  0 return enterface;
648    }
649   
650    /**
651    * Interface which objects for this table will implement
652    *
653    * @param v
654    * Value to assign to interface.
655    */
 
656  0 toggle public void setInterface(String v) {
657  0 this.enterface = v;
658    }
659   
660    /**
661    * When a table is abstract, it marks the business object class that is generated as being abstract. If you have a
662    * table called "FOO", then the Foo BO will be <code>public abstract class Foo</code> This helps support class
663    * hierarchies
664    *
665    * @return value of abstractValue.
666    */
 
667  0 toggle public boolean isAbstract() {
668  0 return abstractValue;
669    }
670   
671    /**
672    * When a table is abstract, it marks the business object class that is generated as being abstract. If you have a
673    * table called "FOO", then the Foo BO will be <code>public abstract class Foo</code> This helps support class
674    * hierarchies
675    *
676    * @param v
677    * Value to assign to abstractValue.
678    */
 
679  0 toggle public void setAbstract(boolean v) {
680  0 this.abstractValue = v;
681    }
682   
683    /**
684    * Get the value of package.
685    *
686    * @return value of package.
687    */
 
688  0 toggle public String getPackage() {
689  0 if (pkg != null) {
690  0 return pkg;
691    } else {
692  0 return this.getDatabase().getPackage();
693    }
694    }
695   
696    /**
697    * Set the value of package.
698    *
699    * @param v
700    * Value to assign to package.
701    */
 
702  0 toggle public void setPackage(String v) {
703  0 this.pkg = v;
704    }
705   
706    /**
707    * Returns a List containing all the columns in the table
708    *
709    * @return a List containing all the columns
710    */
 
711  0 toggle public List getColumns() {
712  0 return columnList;
713    }
714   
715    /**
716    * Utility method to get the number of columns in this table
717    */
 
718  0 toggle public int getNumColumns() {
719  0 return columnList.size();
720    }
721   
722    /**
723    * Returns a List containing all the FKs in the table
724    *
725    * @return a List containing all the FKs
726    */
 
727  0 toggle public List getForeignKeys() {
728  0 return foreignKeys;
729    }
730   
731    /**
732    * Returns a Collection of parameters relevant for the chosen id generation method.
733    */
 
734  0 toggle public List getIdMethodParameters() {
735  0 return idMethodParameters;
736    }
737   
738    /**
739    * A name to use for creating a sequence if one is not specified.
740    *
741    * @return name of the sequence
742    */
 
743  0 toggle public String getSequenceName() {
744  0 String result = null;
745  0 if (getIdMethod().equals(NATIVE)) {
746  0 List idMethodParams = getIdMethodParameters();
747  0 if (idMethodParams == null) {
748  0 result = getName() + "_SEQ";
749    } else {
750  0 result = ((IdMethodParameter) idMethodParams.get(0)).getValue();
751    }
752    }
753  0 return result;
754    }
755   
756    /**
757    * Returns a List containing all the indices in the table
758    *
759    * @return A List containing all the indices
760    */
 
761  0 toggle public List getIndices() {
762  0 return indices;
763    }
764   
765    /**
766    * Returns a List containing all the UKs in the table
767    *
768    * @return A List containing all the UKs
769    */
 
770  0 toggle public List getUnices() {
771  0 return unices;
772    }
773   
774    /**
775    * Returns a specified column.
776    *
777    * @param name
778    * name of the column
779    * @return Return a Column object or null if it does not exist.
780    */
 
781  0 toggle public Column getColumn(String name) {
782  0 return (Column) columnsByName.get(name);
783    }
784   
785    /**
786    * Returns a specified column.
787    *
788    * @param javaName
789    * java name of the column
790    * @return Return a Column object or null if it does not exist.
791    */
 
792  0 toggle public Column getColumnByJavaName(String javaName) {
793  0 return (Column) columnsByJavaName.get(javaName);
794    }
795   
796    /**
797    * Return the first foreign key that includes col in it's list of local columns. Eg. Foreign key (a,b,c) refrences
798    * tbl(x,y,z) will be returned of col is either a,b or c.
799    *
800    * @param col
801    * column name included in the key
802    * @return Return a Column object or null if it does not exist.
803    */
 
804  0 toggle public ForeignKey getForeignKey(String col) {
805  0 ForeignKey firstFK = null;
806  0 for (Iterator iter = foreignKeys.iterator(); iter.hasNext();) {
807  0 ForeignKey key = (ForeignKey) iter.next();
808  0 if (key.getLocalColumns().contains(col)) {
809  0 if (firstFK == null) {
810  0 firstFK = key;
811    } else {
812    // System.out.println(col+" is in multiple FKs. This is not"
813    // + " being handled properly.");
814    // throw new IllegalStateException("Cannot call method if " +
815    // "column is referenced multiple times");
816    }
817    }
818    }
819  0 return firstFK;
820    }
821   
822    /**
823    * Returns true if the table contains a specified column
824    *
825    * @param col
826    * the column
827    * @return true if the table contains the column
828    */
 
829  0 toggle public boolean containsColumn(Column col) {
830  0 return columnList.contains(col);
831    }
832   
833    /**
834    * Returns true if the table contains a specified column
835    *
836    * @param name
837    * name of the column
838    * @return true if the table contains the column
839    */
 
840  0 toggle public boolean containsColumn(String name) {
841  0 return (getColumn(name) != null);
842    }
843   
844    /**
845    * Set the parent of the table
846    *
847    * @param parent
848    * the parant database
849    */
 
850  0 toggle public void setDatabase(Database parent) {
851  0 tableParent = parent;
852    }
853   
854    /**
855    * Get the parent of the table
856    *
857    * @return the parant database
858    */
 
859  0 toggle public Database getDatabase() {
860  0 return tableParent;
861    }
862   
863    /**
864    * Flag to determine if code/sql gets created for this table. Table will be skipped, if return true.
865    *
866    * @return value of forReferenceOnly.
867    */
 
868  0 toggle public boolean isForReferenceOnly() {
869  0 return forReferenceOnly;
870    }
871   
872    /**
873    * Flag to determine if code/sql gets created for this table. Table will be skipped, if set to true.
874    *
875    * @param v
876    * Value to assign to forReferenceOnly.
877    */
 
878  0 toggle public void setForReferenceOnly(boolean v) {
879  0 this.forReferenceOnly = v;
880    }
881   
882    /**
883    * Returns a XML representation of this table.
884    *
885    * @return XML representation of this table
886    */
 
887  0 toggle public String toString() {
888  0 StringBuffer result = new StringBuffer();
889   
890  0 result.append("<table name=\"").append(name).append('\"');
891   
892  0 if (javaName != null) {
893  0 result.append(" javaName=\"").append(javaName).append('\"');
894    }
895   
896  0 if (idMethod != null) {
897  0 result.append(" idMethod=\"").append(idMethod).append('\"');
898    }
899   
900  0 if (skipSql) {
901  0 result.append(" skipSql=\"").append(new Boolean(skipSql)).append('\"');
902    }
903   
904  0 if (abstractValue) {
905  0 result.append(" abstract=\"").append(new Boolean(abstractValue)).append('\"');
906    }
907   
908  0 if (baseClass != null) {
909  0 result.append(" baseClass=\"").append(baseClass).append('\"');
910    }
911   
912  0 if (basePeer != null) {
913  0 result.append(" basePeer=\"").append(basePeer).append('\"');
914    }
915   
916  0 result.append(">\n");
917   
918  0 if (columnList != null) {
919  0 for (Iterator iter = columnList.iterator(); iter.hasNext();) {
920  0 result.append(iter.next());
921    }
922    }
923   
924  0 if (foreignKeys != null) {
925  0 for (Iterator iter = foreignKeys.iterator(); iter.hasNext();) {
926  0 result.append(iter.next());
927    }
928    }
929   
930  0 if (idMethodParameters != null) {
931  0 Iterator iter = idMethodParameters.iterator();
932  0 while (iter.hasNext()) {
933  0 result.append(iter.next());
934    }
935    }
936   
937  0 result.append("</table>\n");
938   
939  0 return result.toString();
940    }
941   
942    /**
943    * Returns the collection of Columns which make up the single primary key for this table.
944    *
945    * @return A list of the primary key parts.
946    */
 
947  0 toggle public List getPrimaryKey() {
948  0 List pk = new ArrayList(columnList.size());
949   
950  0 Iterator iter = columnList.iterator();
951  0 while (iter.hasNext()) {
952  0 Column col = (Column) iter.next();
953  0 if (col.isPrimaryKey()) {
954  0 pk.add(col);
955    }
956    }
957  0 return pk;
958    }
959   
960    /**
961    * Determine whether this table has a primary key.
962    *
963    * @return Whether this table has any primary key parts.
964    */
 
965  0 toggle public boolean hasPrimaryKey() {
966  0 return (getPrimaryKey().size() > 0);
967    }
968   
969    /**
970    * Returns all parts of the primary key, separated by commas.
971    *
972    * @return A CSV list of primary key parts.
973    */
 
974  0 toggle public String printPrimaryKey() {
975  0 return printList(columnList);
976    }
977   
978    /**
979    * Returns the elements of the list, separated by commas.
980    *
981    * @param list
982    * a list of Columns
983    * @return A CSV list.
984    */
 
985  0 toggle private String printList(List list) {
986  0 StringBuffer result = new StringBuffer();
987  0 boolean comma = false;
988  0 for (Iterator iter = list.iterator(); iter.hasNext();) {
989  0 Column col = (Column) iter.next();
990  0 if (col.isPrimaryKey()) {
991  0 if (comma) {
992  0 result.append(',');
993    } else {
994  0 comma = true;
995    }
996  0 result.append(col.getName());
997    }
998    }
999  0 return result.toString();
1000    }
1001   
1002    /**
1003    * Force all columns to set the correctGetters property.
1004    *
1005    * @param value
1006    * The new value of the correctGetters property.
1007    * @since 3.2
1008    */
 
1009  0 toggle public void setCorrectGetters(Boolean value) {
1010  0 boolean correctGetters = value != null && value.booleanValue();
1011  0 for (Iterator it = columnList.iterator(); it.hasNext();) {
1012  0 Column col = (Column) it.next();
1013  0 col.setCorrectGetters(correctGetters);
1014    }
1015    }
1016   
1017    /**
1018    * Add an XML Specified option key/value pair to this element's option set.
1019    *
1020    * @param key
1021    * the key of the option.
1022    * @param value
1023    * the value of the option.
1024    */
 
1025  0 toggle public void addOption(String key, String value) {
1026  0 options.put(key, value);
1027    }
1028   
1029    /**
1030    * Get the value that was associated with this key in an XML option element.
1031    *
1032    * @param key
1033    * the key of the option.
1034    * @return The value for the key or a null.
1035    */
 
1036  0 toggle public String getOption(String key) {
1037  0 return (String) options.get(key);
1038    }
1039   
1040    /**
1041    * Gets the full ordered hashtable array of items specified by XML option statements under this element.
1042    * <p>
1043    *
1044    * Note, this is not thread save but since it's only used for generation which is single threaded, there should be
1045    * minimum danger using this in Velocity.
1046    *
1047    * @return An Map of all options. Will not be null but may be empty.
1048    */
 
1049  0 toggle public Map getOptions() {
1050  0 return options;
1051    }
1052    }