View Javadoc

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