1 package org.apache.torque.engine.database.model;
2
3 /* ====================================================================
4 * The Apache Software License, Version 1.1
5 *
6 * Copyright (c) 2001-2003 The Apache Software Foundation. All rights
7 * reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
19 * distribution.
20 *
21 * 3. The end-user documentation included with the redistribution,
22 * if any, must include the following acknowledgment:
23 * "This product includes software developed by the
24 * Apache Software Foundation (http://www.apache.org/)."
25 * Alternately, this acknowledgment may appear in the software itself,
26 * if and wherever such third-party acknowledgments normally appear.
27 *
28 * 4. The names "Apache" and "Apache Software Foundation" and
29 * "Apache Turbine" must not be used to endorse or promote products
30 * derived from this software without prior written permission. For
31 * written permission, please contact apache@apache.org.
32 *
33 * 5. Products derived from this software may not be called "Apache",
34 * "Apache Turbine", nor may "Apache" appear in their name, without
35 * prior written permission of the Apache Software Foundation.
36 *
37 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
41 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48 * SUCH DAMAGE.
49 * ====================================================================
50 *
51 * This software consists of voluntary contributions made by many
52 * individuals on behalf of the Apache Software Foundation. For more
53 * information on the Apache Software Foundation, please see
54 * <http://www.apache.org/>.
55 */
56
57 import java.util.ArrayList;
58 import java.util.Date;
59 import java.util.Hashtable;
60 import java.util.List;
61
62 import org.apache.commons.lang.StringUtils;
63
64 import org.apache.commons.logging.Log;
65 import org.apache.commons.logging.LogFactory;
66
67 import org.apache.torque.engine.EngineException;
68
69 import org.xml.sax.Attributes;
70
71 /***
72 * A Class for holding data about a column used in an Application.
73 *
74 * @author <a href="mailto:leon@opticode.co.za">Leon Messerschmidt</a>
75 * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
76 * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
77 * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
78 * @author <a href="mailto:byron_foster@byron_foster@yahoo.com>Byron Foster</a>
79 * @version $Id: Column.java,v 1.5 2003/08/08 09:15:12 mpoeschl Exp $
80 */
81 public class Column
82 {
83 /*** Logging class from commons.logging */
84 private static Log log = LogFactory.getLog(Column.class);
85 private String name;
86 private String description;
87 private String javaName = null;
88 private String javaNamingMethod;
89 private boolean isNotNull = false;
90 private String size;
91 /*** type as defined in schema.xml */
92 private String torqueType;
93 private String javaType;
94 private Object columnType;
95 private Table parentTable;
96 private int position;
97 private boolean isPrimaryKey = false;
98 private boolean isUnique = false;
99 private boolean isAutoIncrement = false;
100 private String defaultValue;
101 private List referrers;
102 // only one type is supported currently, which assumes the
103 // column either contains the classnames or a key to
104 // classnames specified in the schema. Others may be
105 // supported later.
106 private String inheritanceType;
107 private boolean isInheritance;
108 private boolean isEnumeratedClasses;
109 private List inheritanceList;
110 private boolean needsTransactionInPostgres;
111
112 /*** class name to do input validation on this column */
113 private String inputValidator = null;
114
115 /***
116 * Creates a new instance with a <code>null</code> name.
117 */
118 public Column()
119 {
120 this(null);
121 }
122
123 /***
124 * Creates a new column and set the name
125 *
126 * @param name column name
127 */
128 public Column(String name)
129 {
130 this.name = name;
131 }
132
133 /***
134 * Return a comma delimited string listing the specified columns.
135 *
136 * @param columns Either a list of <code>Column</code> objects, or
137 * a list of <code>String</code> objects with column names.
138 */
139 public static String makeList(List columns)
140 {
141 Object obj = columns.get(0);
142 boolean isColumnList = (obj instanceof Column);
143 if (isColumnList)
144 {
145 obj = ((Column) obj).getName();
146 }
147 StringBuffer buf = new StringBuffer((String) obj);
148 for (int i = 1; i < columns.size(); i++)
149 {
150 obj = columns.get(i);
151 if (isColumnList)
152 {
153 obj = ((Column) obj).getName();
154 }
155 buf.append(", ").append(obj);
156 }
157 return buf.toString();
158 }
159
160 /***
161 * Imports a column from an XML specification
162 */
163 public void loadFromXML(Attributes attrib)
164 {
165 //Name
166 name = attrib.getValue("name");
167
168 javaName = attrib.getValue("javaName");
169 javaType = attrib.getValue("javaType");
170 if (javaType != null && javaType.length() == 0)
171 {
172 javaType = null;
173 }
174
175 // retrieves the method for converting from specified name to
176 // a java name.
177 javaNamingMethod = attrib.getValue("javaNamingMethod");
178 if (javaNamingMethod == null)
179 {
180 javaNamingMethod
181 = parentTable.getDatabase().getDefaultJavaNamingMethod();
182 }
183
184 //Primary Key
185 String primaryKey = attrib.getValue("primaryKey");
186 //Avoid NullPointerExceptions on string comparisons.
187 isPrimaryKey = ("true".equals (primaryKey));
188
189 // If this column is a primary key then it can't be null.
190 if ("true".equals (primaryKey))
191 {
192 isNotNull = true;
193 }
194
195 // HELP: Should primary key, index, and/or idMethod="native"
196 // affect isNotNull? If not, please document why here.
197 String notNull = attrib.getValue("required");
198 isNotNull = (notNull != null && "true".equals(notNull));
199
200 //AutoIncrement/Sequences
201 String autoIncrement = attrib.getValue("autoIncrement");
202 isAutoIncrement = ("true".equals(autoIncrement));
203
204 //Default column value.
205 defaultValue = attrib.getValue("default");
206
207 size = attrib.getValue("size");
208
209 setType(attrib.getValue("type"));
210
211 inheritanceType = attrib.getValue("inheritance");
212 isInheritance = (inheritanceType != null
213 && !inheritanceType.equals("false"));
214
215 this.inputValidator = attrib.getValue("inputValidator");
216 description = attrib.getValue("description");
217 }
218
219 /***
220 * Returns table.column
221 */
222 public String getFullyQualifiedName()
223 {
224 return (parentTable.getName() + '.' + name);
225 }
226
227 /***
228 * Get the name of the column
229 */
230 public String getName()
231 {
232 return name;
233 }
234
235 /***
236 * Set the name of the column
237 */
238 public void setName(String newName)
239 {
240 name = newName;
241 }
242
243 /***
244 * Get the description for the Table
245 */
246 public String getDescription()
247 {
248 return description;
249 }
250
251 /***
252 * Set the description for the Table
253 *
254 * @param newDescription description for the Table
255 */
256 public void setDescription(String newDescription)
257 {
258 description = newDescription;
259 }
260
261 /***
262 * Get name to use in Java sources to build method names.
263 *
264 * @return the capitalised javaName
265 */
266 public String getJavaName()
267 {
268 if (javaName == null)
269 {
270 List inputs = new ArrayList(2);
271 inputs.add(name);
272 inputs.add(javaNamingMethod);
273 try
274 {
275 javaName = NameFactory.generateName(NameFactory.JAVA_GENERATOR,
276 inputs);
277 }
278 catch (EngineException e)
279 {
280 log.error(e, e);
281 }
282 }
283 return StringUtils.capitalise(javaName);
284 }
285
286 /***
287 * Get variable name to use in Java sources (= uncapitalised java name)
288 */
289 public String getUncapitalisedJavaName()
290 {
291 return StringUtils.uncapitalise(getJavaName());
292 }
293
294 /***
295 * Set name to use in Java sources
296 */
297 public void setJavaName(String javaName)
298 {
299 this.javaName = javaName;
300 }
301
302 /***
303 * Get type to use in Java sources
304 */
305 public String getJavaType()
306 {
307 return javaType;
308 }
309
310 /***
311 * Get the location of this column within the table (one-based).
312 * @return value of position.
313 */
314 public int getPosition()
315 {
316 return position;
317 }
318
319 /***
320 * Get the location of this column within the table (one-based).
321 * @param v Value to assign to position.
322 */
323 public void setPosition(int v)
324 {
325 this.position = v;
326 }
327
328 /***
329 * Set the parent Table of the column
330 */
331 public void setTable(Table parent)
332 {
333 parentTable = parent;
334 }
335
336 /***
337 * Get the parent Table of the column
338 */
339 public Table getTable()
340 {
341 return parentTable;
342 }
343
344 /***
345 * Returns the Name of the table the column is in
346 */
347 public String getTableName()
348 {
349 return parentTable.getName();
350 }
351
352 /***
353 * A utility function to create a new column
354 * from attrib and add it to this table.
355 */
356 public Inheritance addInheritance(Attributes attrib)
357 {
358 Inheritance inh = new Inheritance();
359 inh.loadFromXML (attrib);
360 addInheritance(inh);
361
362 return inh;
363 }
364
365 /***
366 * Adds a new inheritance definition to the inheritance list and set the
367 * parent column of the inheritance to the current column
368 */
369 public void addInheritance(Inheritance inh)
370 {
371 inh.setColumn(this);
372 if (inheritanceList == null)
373 {
374 inheritanceList = new ArrayList();
375 isEnumeratedClasses = true;
376 }
377 inheritanceList.add(inh);
378 }
379
380 /***
381 * Get the inheritance definitions.
382 */
383 public List getChildren()
384 {
385 return inheritanceList;
386 }
387
388 /***
389 * Determine if this column is a normal property or specifies a
390 * the classes that are represented in the table containing this column.
391 */
392 public boolean isInheritance()
393 {
394 return isInheritance;
395 }
396
397 /***
398 * Determine if possible classes have been enumerated in the xml file.
399 */
400 public boolean isEnumeratedClasses()
401 {
402 return isEnumeratedClasses;
403 }
404
405 /***
406 * Return the isNotNull property of the column
407 */
408 public boolean isNotNull()
409 {
410 return isNotNull;
411 }
412
413 /***
414 * Set the isNotNull property of the column
415 */
416 public void setNotNull(boolean status)
417 {
418 isNotNull = status;
419 }
420
421 /***
422 * Set if the column is a primary key or not
423 */
424 public void setPrimaryKey(boolean pk)
425 {
426 isPrimaryKey = pk;
427 }
428
429 /***
430 * Return true if the column is a primary key
431 */
432 public boolean isPrimaryKey()
433 {
434 return isPrimaryKey;
435 }
436
437 /***
438 * Set true if the column is UNIQUE
439 */
440 public void setUnique (boolean u)
441 {
442 isUnique = u;
443 }
444
445 /***
446 * Get the UNIQUE property
447 */
448 public boolean isUnique()
449 {
450 return isUnique;
451 }
452
453 /***
454 * Return true if the column requires a transaction in Postgres
455 */
456 public boolean requiresTransactionInPostgres()
457 {
458 return needsTransactionInPostgres;
459 }
460
461 /***
462 * Utility method to determine if this column is a foreign key.
463 */
464 public boolean isForeignKey()
465 {
466 return (getForeignKey() != null);
467 }
468
469 /***
470 * Determine if this column is a foreign key that refers to the
471 * same table as another foreign key column in this table.
472 */
473 public boolean isMultipleFK()
474 {
475 ForeignKey fk = getForeignKey();
476 if (fk != null)
477 {
478 ForeignKey[] fks = parentTable.getForeignKeys();
479 for (int i = 0; i < fks.length; i++)
480 {
481 if (fks[i].getForeignTableName()
482 .equals(fk.getForeignTableName())
483 && !fks[i].getLocalColumns().contains(this.name))
484 {
485 return true;
486 }
487 }
488 }
489
490 // No multiple foreign keys.
491 return false;
492 }
493
494 /***
495 * get the foreign key object for this column
496 * if it is a foreign key or part of a foreign key
497 */
498 public ForeignKey getForeignKey()
499 {
500 return parentTable.getForeignKey (this.name);
501 }
502
503 /***
504 * Utility method to get the related table of this column if it is a foreign
505 * key or part of a foreign key
506 */
507 public String getRelatedTableName()
508 {
509 ForeignKey fk = getForeignKey();
510 return (fk == null ? null : fk.getForeignTableName());
511 }
512
513
514 /***
515 * Utility method to get the related column of this local column if this
516 * column is a foreign key or part of a foreign key.
517 */
518 public String getRelatedColumnName()
519 {
520 ForeignKey fk = getForeignKey();
521 if (fk == null)
522 {
523 return null;
524 }
525 else
526 {
527 return fk.getLocalForeignMapping().get(this.name).toString();
528 }
529 }
530
531 /***
532 * Adds the foreign key from another table that refers to this column.
533 */
534 public void addReferrer(ForeignKey fk)
535 {
536 if (referrers == null)
537 {
538 referrers = new ArrayList(5);
539 }
540 referrers.add(fk);
541 }
542
543 /***
544 * Get list of references to this column.
545 */
546 public List getReferrers()
547 {
548 if (referrers == null)
549 {
550 referrers = new ArrayList(5);
551 }
552 return referrers;
553 }
554
555 /***
556 * Returns the colunm type
557 */
558 public void setType(String torqueType)
559 {
560 this.torqueType = torqueType;
561 if (torqueType.equals("VARBINARY") || torqueType.equals("BLOB"))
562 {
563 needsTransactionInPostgres = true;
564 }
565 }
566
567 /***
568 * Returns the column jdbc type as an object
569 */
570 public Object getType()
571 {
572 return TypeMap.getJdbcType(torqueType);
573 }
574
575 /***
576 * Returns the column type as given in the schema as an object
577 */
578 public Object getTorqueType()
579 {
580 return torqueType;
581 }
582
583 /***
584 * Utility method to see if the column is a string
585 */
586 public boolean isString()
587 {
588 return (columnType instanceof String);
589 }
590
591 /***
592 * Utility method to return the value as an element to be usable
593 * in an SQL insert statement. This is used from the SQL loader task
594 */
595 public boolean needEscapedValue()
596 {
597 return (torqueType != null) &&
598 ( torqueType.equals("VARCHAR")
599 || torqueType.equals("LONGVARCHAR")
600 || torqueType.equals("DATE")
601 || torqueType.equals("DATETIME")
602 || torqueType.equals("TIMESTAMP")
603 || torqueType.equals("CHAR"));
604 }
605
606 /***
607 * String representation of the column. This is an xml representation.
608 *
609 * @return string representation in xml
610 */
611 public String toString()
612 {
613 StringBuffer result = new StringBuffer();
614 result.append(" <column name=\"").append(name).append('"');
615
616 if (javaName != null)
617 {
618 result.append(" javaName=\"").append(javaName).append('"');
619 }
620
621 if (isPrimaryKey)
622 {
623 result.append(" primaryKey=\"").append(isPrimaryKey).append('"');
624 }
625
626 if (isNotNull)
627 {
628 result.append(" required=\"true\"");
629 }
630 else
631 {
632 result.append(" required=\"false\"");
633 }
634
635 result.append(" type=\"").append (torqueType).append('"');
636
637 if (size != null)
638 {
639 result.append(" size=\"").append(size).append('"');
640 }
641
642 if (defaultValue != null)
643 {
644 result.append(" default=\"").append(defaultValue).append('"');
645 }
646
647 if (isInheritance())
648 {
649 result.append(" inheritance=\"").append(inheritanceType)
650 .append('"');
651 }
652
653 // Close the column.
654 result.append(" />\n");
655
656 return result.toString();
657 }
658
659 /***
660 * Returns the size of the column
661 */
662 public String getSize()
663 {
664 return size;
665 }
666
667 /***
668 * Set the size of the column
669 */
670 public void setSize(String newSize)
671 {
672 size = newSize;
673 }
674
675 /***
676 * Return the size in brackets for use in an sql
677 * schema if the type is String. Otherwise return an empty string
678 */
679 public String printSize()
680 {
681 return (size == null ? "" : '(' + size + ')');
682 }
683
684 /***
685 * Return a string that will give this column a default value.
686 * <p>
687 * TODO: Properly SQL-escape text values.
688 */
689 public String getDefaultSetting()
690 {
691 StringBuffer dflt = new StringBuffer(0);
692 if (defaultValue != null)
693 {
694 dflt.append("default ");
695 if (TypeMap.isTextType(torqueType))
696 {
697 // TODO: Properly SQL-escape the text.
698 dflt.append('\'').append(defaultValue).append('\'');
699 }
700 else
701 {
702 dflt.append(defaultValue);
703 }
704 }
705 return dflt.toString();
706 }
707
708 /***
709 * Set a string that will give this column a default value.
710 */
711 public void setDefaultValue(String def)
712 {
713 defaultValue = def;
714 }
715
716 /***
717 * Get a string that will give this column a default value.
718 */
719 public String getDefaultValue()
720 {
721 return defaultValue;
722 }
723
724 /***
725 * Returns the class name to do input validation
726 */
727 public String getInputValidator()
728 {
729 return this.inputValidator;
730 }
731
732 /***
733 * Return auto increment/sequence string for the target database. We need to
734 * pass in the props for the target database!
735 */
736 public boolean isAutoIncrement()
737 {
738 return isAutoIncrement;
739 }
740
741 /***
742 * Set the auto increment value.
743 * Use isAutoIncrement() to find out if it is set or not.
744 */
745 public void setAutoIncrement(boolean value)
746 {
747 isAutoIncrement = value;
748 }
749
750 /***
751 * Set the column type from a string property
752 * (normally a string from an sql input file)
753 */
754 public void setTypeFromString (String typeName, String size)
755 {
756 String tn = typeName.toUpperCase();
757 setType(tn);
758
759 if (size != null)
760 {
761 this.size = size;
762 }
763
764 if (tn.indexOf ("CHAR") != -1)
765 {
766 torqueType = "VARCHAR";
767 columnType = "";
768 }
769 else if (tn.indexOf ("INT") != -1)
770 {
771 torqueType = "INTEGER";
772 columnType = new Integer (0);
773 }
774 else if (tn.indexOf ("FLOAT") != -1)
775 {
776 torqueType = "FLOAT";
777 columnType = new Float (0);
778 }
779 else if (tn.indexOf ("DATE") != -1)
780 {
781 torqueType = "DATE";
782 columnType = new Date();
783 }
784 else if (tn.indexOf ("TIME") != -1)
785 {
786 torqueType = "TIMESTAMP";
787 columnType = new Date();
788 }
789 else if (tn.indexOf ("BINARY") != -1)
790 {
791 torqueType = "LONGVARBINARY";
792 columnType = new Hashtable();
793 }
794 else
795 {
796 torqueType = "VARCHAR";
797 columnType = "";
798 }
799 }
800
801 /***
802 * Return a string representation of the
803 * Java object which corresponds to the JDBC
804 * type of this column. Use in the generation
805 * of MapBuilders.
806 */
807 public String getJavaObject()
808 {
809 return TypeMap.getJavaObject(torqueType);
810 }
811
812 /***
813 * Return a string representation of the primitive java type which
814 * corresponds to the JDBC type of this column.
815 *
816 * @return string representation of the primitive java type
817 */
818 public String getJavaPrimitive()
819 {
820 return TypeMap.getJavaNative(torqueType);
821 }
822
823 /***
824 * Return a string representation of the native java type which corresponds
825 * to the JDBC type of this column. Use in the generation of Base objects.
826 * This method is used by torque, so it returns Key types for primaryKey and
827 * foreignKey columns
828 *
829 * @return java datatype used by torque
830 */
831 public String getJavaNative()
832 {
833 String jtype = TypeMap.getJavaNativeObject(torqueType);
834 if (isUsePrimitive())
835 {
836 jtype = TypeMap.getJavaNative(torqueType);
837 }
838
839 return jtype;
840 }
841
842 /***
843 * Return Village asX() method which corresponds to the JDBC type
844 * which represents this column.
845 */
846 public String getVillageMethod()
847 {
848 String vmethod = TypeMap.getVillageObjectMethod(torqueType);
849 if (isUsePrimitive())
850 {
851 vmethod = TypeMap.getVillageMethod(torqueType);
852 }
853
854 return vmethod;
855 }
856
857 /***
858 * Return ParameterParser getX() method which
859 * corresponds to the JDBC type which represents this column.
860 */
861 public String getParameterParserMethod()
862 {
863 return TypeMap.getPPMethod(torqueType);
864 }
865
866 /***
867 * Returns true if the column type is boolean in the
868 * java object and a numeric (1 or 0) in the db.
869 */
870 public boolean isBooleanInt()
871 {
872 return TypeMap.isBooleanInt(torqueType);
873 }
874
875 /***
876 * Returns true if the column type is boolean in the
877 * java object and a String ("Y" or "N") in the db.
878 */
879 public boolean isBooleanChar()
880 {
881 return TypeMap.isBooleanChar(torqueType);
882 }
883
884 /***
885 * returns true, if the columns java native type is an
886 * boolean, byte, short, int, long, float, double, char
887 */
888 public boolean isPrimitive()
889 {
890 String t = getJavaNative();
891 return "boolean".equals(t)
892 || "byte".equals(t)
893 || "short".equals(t)
894 || "int".equals(t)
895 || "long".equals(t)
896 || "float".equals(t)
897 || "double".equals(t)
898 || "char".equals(t);
899 }
900
901 public boolean isUsePrimitive()
902 {
903 String s = getJavaType();
904 return (s != null && s.equals("primitive"))
905 || (s == null && !"object".equals(
906 getTable().getDatabase().getDefaultJavaType()));
907 }
908 }
This page was automatically generated by Maven