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