1 package org.apache.torque.engine.database.model;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
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
116
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
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
159
160 if (heavyIndexing)
161 {
162 doHeavyIndexing();
163 }
164
165
166
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
200
201
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
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
937
938
939
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 }