001    package org.apache.torque.engine.database.model;
002    
003    /*
004     * Licensed to the Apache Software Foundation (ASF) under one
005     * or more contributor license agreements.  See the NOTICE file
006     * distributed with this work for additional information
007     * regarding copyright ownership.  The ASF licenses this file
008     * to you under the Apache License, Version 2.0 (the
009     * "License"); you may not use this file except in compliance
010     * with the License.  You may obtain a copy of the License at
011     *
012     *   http://www.apache.org/licenses/LICENSE-2.0
013     *
014     * Unless required by applicable law or agreed to in writing,
015     * software distributed under the License is distributed on an
016     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017     * KIND, either express or implied.  See the License for the
018     * specific language governing permissions and limitations
019     * under the License.
020     */
021    
022    import java.util.ArrayList;
023    import java.util.Collections;
024    import java.util.Iterator;
025    import java.util.List;
026    import java.util.Map;
027    
028    import org.apache.commons.collections.map.ListOrderedMap;
029    import org.apache.commons.lang.StringUtils;
030    import org.apache.commons.logging.Log;
031    import org.apache.commons.logging.LogFactory;
032    import org.apache.torque.engine.EngineException;
033    import org.apache.torque.engine.platform.Platform;
034    import org.apache.torque.engine.platform.PlatformDefaultImpl;
035    import org.xml.sax.Attributes;
036    
037    /**
038     * A Class for holding data about a column used in an Application.
039     * 
040     * @author <a href="mailto:leon@opticode.co.za">Leon Messerschmidt</a>
041     * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
042     * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
043     * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
044     * @author <a href="mailto:byron_foster@byron_foster@yahoo.com>Byron Foster</a>
045     * @author <a href="mailto:mpoeschl@marmot.at>Martin Poeschl</a>
046     * @author <a href="mailto:monroe@dukece.com>Greg Monroe</a>
047     * @version $Id: Column.java,v 1.1 2007-10-21 07:57:27 abyrne Exp $
048     */
049    public class Column {
050            private static final SchemaType DEFAULT_TYPE = SchemaType.VARCHAR;
051            /** Logging class from commons.logging */
052            private static Log log = LogFactory.getLog(Column.class);
053            private String name;
054            private String description;
055            private Domain domain = new Domain();
056            private String javaName = null;
057            private String javaNamingMethod;
058            private boolean isNotNull = false;
059            private boolean isProtected = false;
060            private String javaType;
061            private Table parentTable;
062            private int position;
063            private boolean isPrimaryKey = false;
064            private boolean isUnique = false;
065            private boolean isAutoIncrement = false;
066            private List referrers;
067            // only one type is supported currently, which assumes the
068            // column either contains the classnames or a key to
069            // classnames specified in the schema. Others may be
070            // supported later.
071            private String inheritanceType;
072            private boolean isInheritance;
073            private boolean isEnumeratedClasses;
074            private List inheritanceList;
075            private boolean needsTransactionInPostgres;
076            /**
077             * The type from java.sql.Types
078             */
079            private int jdbcType;
080    
081            /** generate is... setters for boolean columns if true */
082            private boolean correctGetters = false;
083    
084            /** class name to do input validation on this column */
085            private String inputValidator = null;
086            private Map options;
087    
088            /**
089             * Creates a new instance with a <code>null</code> name.
090             */
091            public Column() {
092                    this(null);
093            }
094    
095            /**
096             * Creates a new column and set the name
097             * 
098             * @param name
099             *            column name
100             */
101            public Column(String name) {
102                    this.name = name;
103                    options = Collections.synchronizedMap(new ListOrderedMap());
104            }
105    
106            /**
107             * Return a comma delimited string listing the specified columns.
108             * 
109             * @param columns
110             *            Either a list of <code>Column</code> objects, or a list of <code>String</code> objects with column
111             *            names.
112             */
113            public static String makeList(List columns) {
114                    Object obj = columns.get(0);
115                    boolean isColumnList = (obj instanceof Column);
116                    if (isColumnList) {
117                            obj = ((Column) obj).getName();
118                    }
119                    StringBuffer buf = new StringBuffer((String) obj);
120                    for (int i = 1; i < columns.size(); i++) {
121                            obj = columns.get(i);
122                            if (isColumnList) {
123                                    obj = ((Column) obj).getName();
124                            }
125                            buf.append(", ").append(obj);
126                    }
127                    return buf.toString();
128            }
129    
130            /**
131             * Imports a column from an XML specification
132             */
133            public void loadFromXML(Attributes attrib) {
134                    String dom = attrib.getValue("domain");
135                    if (StringUtils.isNotEmpty(dom)) {
136                            domain = new Domain(getTable().getDatabase().getDomain(dom));
137                    } else {
138                            domain = new Domain(getPlatform().getDomainForSchemaType(DEFAULT_TYPE));
139                            setType(attrib.getValue("type"));
140                    }
141                    // Name
142                    name = attrib.getValue("name");
143    
144                    javaName = attrib.getValue("javaName");
145                    javaType = attrib.getValue("javaType");
146                    if (javaType != null && javaType.length() == 0) {
147                            javaType = null;
148                    }
149    
150                    // retrieves the method for converting from specified name to
151                    // a java name.
152                    javaNamingMethod = attrib.getValue("javaNamingMethod");
153                    if (javaNamingMethod == null) {
154                            javaNamingMethod = parentTable.getDatabase().getDefaultJavaNamingMethod();
155                    }
156    
157                    // Primary Key
158                    String primaryKey = attrib.getValue("primaryKey");
159                    // Avoid NullPointerExceptions on string comparisons.
160                    isPrimaryKey = ("true".equals(primaryKey));
161    
162                    // If this column is a primary key then it can't be null.
163                    if ("true".equals(primaryKey)) {
164                            isNotNull = true;
165                    }
166    
167                    // HELP: Should primary key, index, and/or idMethod="native"
168                    // affect isNotNull? If not, please document why here.
169                    String notNull = attrib.getValue("required");
170                    isNotNull = (notNull != null && "true".equals(notNull));
171    
172                    // AutoIncrement/Sequences
173                    String autoIncrement = attrib.getValue("autoIncrement");
174                    // autoincrement is false per default,
175                    // except if the column is a primary key
176                    // and the idMethod is native
177                    // and the platform's default id Method is identity
178                    // and autoIncrement is not excplicitly set to false
179                    isAutoIncrement = ("true".equals(autoIncrement) || (isPrimaryKey() && IDMethod.NATIVE.equals(getTable().getIdMethod()) && Platform.IDENTITY.equals(getPlatform().getNativeIdMethod()) && (!"false".equals(autoIncrement))));
180                    // Default column value.
181                    domain.replaceDefaultValue(attrib.getValue("default"));
182    
183                    domain.replaceSize(attrib.getValue("size"));
184                    domain.replaceScale(attrib.getValue("scale"));
185    
186                    inheritanceType = attrib.getValue("inheritance");
187                    isInheritance = (inheritanceType != null && !inheritanceType.equals("false"));
188    
189                    this.inputValidator = attrib.getValue("inputValidator");
190                    description = attrib.getValue("description");
191    
192                    isProtected = ("true".equals(attrib.getValue("protected")));
193            }
194    
195            /**
196             * Returns table.column
197             */
198            public String getFullyQualifiedName() {
199                    return (parentTable.getName() + '.' + name);
200            }
201    
202            /**
203             * Get the name of the column
204             */
205            public String getName() {
206                    return name;
207            }
208    
209            /**
210             * Set the name of the column
211             */
212            public void setName(String newName) {
213                    name = newName;
214            }
215    
216            /**
217             * Get the description for the Table
218             */
219            public String getDescription() {
220                    return description;
221            }
222    
223            /**
224             * Set the description for the Table
225             * 
226             * @param newDescription
227             *            description for the Table
228             */
229            public void setDescription(String newDescription) {
230                    description = newDescription;
231            }
232    
233            /**
234             * Get name to use in Java sources to build method names.
235             * 
236             * @return the capitalised javaName
237             */
238            public String getJavaName() {
239                    if (javaName == null) {
240                            List inputs = new ArrayList(2);
241                            inputs.add(name);
242                            inputs.add(javaNamingMethod);
243                            try {
244                                    javaName = NameFactory.generateName(NameFactory.JAVA_GENERATOR, inputs);
245                            } catch (EngineException e) {
246                                    log.error(e, e);
247                            }
248                    }
249                    return StringUtils.capitalize(javaName);
250            }
251    
252            /**
253             * Returns the name for the getter method to retrieve the value of this column
254             * 
255             * @return A getter method name for this column.
256             * @since 3.2
257             */
258            public String getGetterName() {
259                    if (("boolean".equalsIgnoreCase(getJavaNative()) && isCorrectGetters())) {
260                            return "is" + StringUtils.capitalize(getJavaName());
261                    } else {
262                            return "get" + StringUtils.capitalize(getJavaName());
263                    }
264            }
265    
266            /**
267             * Returns the name for the setter method to set the value of this column
268             * 
269             * @return A setter method name for this column.
270             * @since 3.2
271             */
272            public String getSetterName() {
273                    return "set" + StringUtils.capitalize(getJavaName());
274            }
275    
276            /**
277             * Get variable name to use in Java sources (= uncapitalised java name)
278             */
279            public String getUncapitalisedJavaName() {
280                    return StringUtils.uncapitalize(getJavaName());
281            }
282    
283            /**
284             * Returns the name of the constant that is used for the column in the Peer class, e.g., RecordPeer.COLVARNAME.
285             * Generally this will be a straight conversion to upper case. But if the column name is equals to TABLE_NAME or
286             * DATABASE_NAME (Torque predefined vars), the column name will have an _ prefixed, e.g. _TABLE_NAME.
287             * <p>
288             * TODO: Handle delimited column names that have non-Java identifier characters in them.
289             * 
290             * @return The name to use in defining the Peer class column variable.
291             */
292            public String getPeerJavaName() {
293                    String peerName = name.toUpperCase();
294                    if (peerName.equals("TABLE_NAME") || peerName.equals("DATABASE_NAME")) {
295                            peerName = "_" + peerName;
296                    }
297                    return peerName;
298            }
299    
300            /**
301             * Set the name to use in Java sources.
302             */
303            public void setJavaName(String javaName) {
304                    this.javaName = javaName;
305            }
306    
307            /**
308             * Returns whether the type in the java object should be an object or primitive.
309             */
310            public String getJavaType() {
311                    return javaType;
312            }
313    
314            /**
315             * Get the location of this column within the table (one-based).
316             * 
317             * @return value of position.
318             */
319            public int getPosition() {
320                    return position;
321            }
322    
323            /**
324             * Get the location of this column within the table (one-based).
325             * 
326             * @param v
327             *            Value to assign to position.
328             */
329            public void setPosition(int v) {
330                    this.position = v;
331            }
332    
333            /**
334             * Set the parent Table of the column
335             */
336            public void setTable(Table parent) {
337                    parentTable = parent;
338            }
339    
340            /**
341             * Get the parent Table of the column
342             */
343            public Table getTable() {
344                    return parentTable;
345            }
346    
347            /**
348             * Returns the Name of the table the column is in
349             */
350            public String getTableName() {
351                    return parentTable.getName();
352            }
353    
354            /**
355             * A utility function to create a new column from attrib and add it to this table.
356             */
357            public Inheritance addInheritance(Attributes attrib) {
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 parent column of the inheritance to the
367             * current column
368             */
369            public void addInheritance(Inheritance inh) {
370                    inh.setColumn(this);
371                    if (inheritanceList == null) {
372                            inheritanceList = new ArrayList();
373                            isEnumeratedClasses = true;
374                    }
375                    inheritanceList.add(inh);
376            }
377    
378            /**
379             * Get the inheritance definitions.
380             */
381            public List getChildren() {
382                    return inheritanceList;
383            }
384    
385            /**
386             * Determine if this column is a normal property or specifies a the classes that are represented in the table
387             * containing this column.
388             */
389            public boolean isInheritance() {
390                    return isInheritance;
391            }
392    
393            /**
394             * Determine if possible classes have been enumerated in the xml file.
395             */
396            public boolean isEnumeratedClasses() {
397                    return isEnumeratedClasses;
398            }
399    
400            /**
401             * Return the isNotNull property of the column
402             */
403            public boolean isNotNull() {
404                    return isNotNull;
405            }
406    
407            /**
408             * Set the isNotNull property of the column
409             */
410            public void setNotNull(boolean status) {
411                    isNotNull = status;
412            }
413    
414            /**
415             * Return NOT NULL String for this column
416             * 
417             * @return "NOT NULL" if null values are not allowed or an empty String.
418             */
419            public String getNotNullString() {
420                    return getTable().getDatabase().getPlatform().getNullString(this.isNotNull());
421            }
422    
423            /**
424             * Return the isProtected property of the column
425             */
426            public boolean isProtected() {
427                    return isProtected;
428            }
429    
430            /**
431             * Set the isProtected property of the Column
432             */
433            public void setProtected(boolean prot) {
434                    isProtected = prot;
435            }
436    
437            /**
438             * Set if the column is a primary key or not
439             */
440            public void setPrimaryKey(boolean pk) {
441                    isPrimaryKey = pk;
442            }
443    
444            /**
445             * Return true if the column is a primary key
446             */
447            public boolean isPrimaryKey() {
448                    return isPrimaryKey;
449            }
450    
451            /**
452             * Set true if the column is UNIQUE
453             */
454            public void setUnique(boolean u) {
455                    isUnique = u;
456            }
457    
458            /**
459             * Get the UNIQUE property
460             */
461            public boolean isUnique() {
462                    return isUnique;
463            }
464    
465            /**
466             * Return true if the column requires a transaction in Postgres
467             */
468            public boolean requiresTransactionInPostgres() {
469                    return needsTransactionInPostgres;
470            }
471    
472            /**
473             * Utility method to determine if this column is a foreign key.
474             */
475            public boolean isForeignKey() {
476                    return (getForeignKey() != null);
477            }
478    
479            /**
480             * Determine if this column is a foreign key that refers to the same table as another foreign key column in this
481             * table.
482             */
483            public boolean isMultipleFK() {
484                    ForeignKey fk = getForeignKey();
485                    if (fk != null) {
486                            Iterator fks = parentTable.getForeignKeys().iterator();
487                            while (fks.hasNext()) {
488                                    ForeignKey key = (ForeignKey) fks.next();
489                                    if (key.getForeignTableName().equals(fk.getForeignTableName()) && !key.getLocalColumns().contains(this.name)) {
490                                            return true;
491                                    }
492                            }
493                    }
494    
495                    // No multiple foreign keys.
496                    return false;
497            }
498    
499            /**
500             * get the foreign key object for this column if it is a foreign key or part of a foreign key
501             */
502            public ForeignKey getForeignKey() {
503                    return parentTable.getForeignKey(this.name);
504            }
505    
506            /**
507             * Utility method to get the related table of this column if it is a foreign key or part of a foreign key
508             */
509            public String getRelatedTableName() {
510                    ForeignKey fk = getForeignKey();
511                    return (fk == null ? null : fk.getForeignTableName());
512            }
513    
514            /**
515             * Utility method to get the related column of this local column if this column is a foreign key or part of a
516             * foreign key.
517             */
518            public String getRelatedColumnName() {
519                    ForeignKey fk = getForeignKey();
520                    if (fk == null) {
521                            return null;
522                    } else {
523                            return fk.getLocalForeignMapping().get(this.name).toString();
524                    }
525            }
526    
527            /**
528             * Adds the foreign key from another table that refers to this column.
529             */
530            public void addReferrer(ForeignKey fk) {
531                    if (referrers == null) {
532                            referrers = new ArrayList(5);
533                    }
534                    referrers.add(fk);
535            }
536    
537            /**
538             * Get list of references to this column.
539             */
540            public List getReferrers() {
541                    if (referrers == null) {
542                            referrers = new ArrayList(5);
543                    }
544                    return referrers;
545            }
546    
547            /**
548             * Sets the colunm type
549             */
550            public void setType(String torqueType) {
551                    SchemaType type = SchemaType.getEnum(torqueType);
552                    if (type == null) {
553                            log.warn("SchemaType " + torqueType + " does not exist");
554                            type = Column.DEFAULT_TYPE;
555                    }
556                    setType(type);
557            }
558    
559            /**
560             * Sets the colunm type
561             */
562            public void setType(SchemaType torqueType) {
563                    domain = new Domain(getPlatform().getDomainForSchemaType(torqueType));
564                    if (torqueType.equals(SchemaType.VARBINARY) || torqueType.equals(SchemaType.BLOB)) {
565                            needsTransactionInPostgres = true;
566                    }
567            }
568    
569            /**
570             * Returns the column jdbc type as an object
571             * 
572             * @deprecated the type conversion is handled by the platform package (since torque 3.2)
573             */
574            public Object getType() {
575                    return TypeMap.getJdbcType(domain.getType()).getName();
576            }
577    
578            /**
579             * Returns the column type as given in the schema as an object
580             */
581            public Object getTorqueType() {
582                    return domain.getType().getName();
583            }
584    
585            /**
586             * Utility method to see if the column is a string
587             * 
588             * @deprecated will be removed after the 3.3 release
589             */
590            public boolean isString() {
591                    return (domain.getType().getName().indexOf("CHAR") != -1);
592            }
593    
594            /**
595             * Utility method to return the value as an element to be usable in an SQL insert statement. This is used from the
596             * SQL loader task
597             */
598            public boolean needEscapedValue() {
599                    String torqueType = domain.getType().getName();
600                    return (torqueType != null) && (torqueType.equals("VARCHAR") || torqueType.equals("LONGVARCHAR") || torqueType.equals("DATE") || torqueType.equals("DATETIME") || torqueType.equals("TIMESTAMP") || torqueType.equals("TIME") || torqueType.equals("CHAR") || torqueType.equals("CLOB"));
601            }
602    
603            /**
604             * String representation of the column. This is an xml representation.
605             * 
606             * @return string representation in xml
607             */
608            public String toString() {
609                    StringBuffer result = new StringBuffer();
610                    result.append("    <column name=\"").append(name).append('"');
611    
612                    if (javaName != null) {
613                            result.append(" javaName=\"").append(javaName).append('"');
614                    }
615    
616                    if (isPrimaryKey) {
617                            result.append(" primaryKey=\"").append(isPrimaryKey).append('"');
618                    }
619    
620                    if (isNotNull) {
621                            result.append(" required=\"true\"");
622                    } else {
623                            result.append(" required=\"false\"");
624                    }
625    
626                    result.append(" type=\"").append(domain.getType().getName()).append('"');
627    
628                    if (domain.getSize() != null) {
629                            result.append(" size=\"").append(domain.getSize()).append('"');
630                    }
631    
632                    if (domain.getScale() != null) {
633                            result.append(" scale=\"").append(domain.getScale()).append('"');
634                    }
635    
636                    if (domain.getDefaultValue() != null) {
637                            result.append(" default=\"").append(domain.getDefaultValue()).append('"');
638                    }
639    
640                    if (isInheritance()) {
641                            result.append(" inheritance=\"").append(inheritanceType).append('"');
642                    }
643    
644                    // Close the column.
645                    result.append(" />\n");
646    
647                    return result.toString();
648            }
649    
650            /**
651             * Returns the size of the column
652             */
653            public String getSize() {
654                    return domain.getSize();
655            }
656    
657            /**
658             * Set the size of the column
659             */
660            public void setSize(String newSize) {
661                    domain.setSize(newSize);
662            }
663    
664            /**
665             * Try to determine the precision of the field from the size attribute. If size attribute is an integer number, it
666             * will be returned. If size attribute is of the format "Precision,Scale", then Precision will be returned. If size
667             * is null or the size value is not an valid integer, null is returned.
668             * <p>
669             * Note: Unparseable values will be logged as a warning.
670             * 
671             * @return The precision portion of the size attribute.
672             */
673            public String getPrecision() {
674                    String size = getSize();
675                    if (size == null) {
676                            return size;
677                    }
678                    int cLoc = size.indexOf(',');
679                    if (cLoc > 0) {
680                            size = size.substring(0, cLoc);
681                    }
682                    try {
683                            Integer.parseInt(size);
684                    } catch (NumberFormatException e) {
685                            log.warn("getPrecision(): Size attribute found (" + getSize() + ") was not an integer number, using default of null!");
686                            size = null;
687                    }
688                    return size;
689            }
690    
691            /**
692             * Try to determine the scale of the field from the scale and size attribute. If scale attribute is an integer
693             * number, it will be returned. If size attribute is of the format "Precision,Scale", then Scale will be returned.
694             * If scale and size attributes are null or the scale value found is not an valid integer, a null value is returned.
695             * <p>
696             * Note: Unparseable values will be logged as a warning.
697             * 
698             * @return The precision portion of the size attribute.
699             */
700            public String getScale() {
701                    String scale = domain.getScale();
702                    // Check for scale on size attribute if no scale attribute
703                    if (scale == null) {
704                            scale = getSize();
705                            if (scale == null) // No scale or size attribute set.
706                            {
707                                    return scale;
708                            }
709                            int cLoc = scale.indexOf(',');
710                            if (cLoc < 0) // Size did not have "P,S" format
711                            {
712                                    return null;
713                            }
714                            scale = scale.substring(cLoc + 1);
715                    }
716    
717                    // Validate that scale string found is integer.
718                    try {
719                            Integer.parseInt(scale);
720                    } catch (NumberFormatException e) {
721                            log.warn("getScale(): Scale (or size=\"p,s\") attribute found (" + scale + ") was not an integer number, using default of null.");
722                            scale = null;
723                    }
724                    return scale;
725            }
726    
727            /**
728             * Set the scale of the column
729             */
730            public void setScale(String newScale) {
731                    domain.setScale(newScale);
732            }
733    
734            /**
735             * Return the size and scale in brackets for use in an sql schema.
736             * 
737             * @return size and scale or an empty String if there are no values available.
738             */
739            public String printSize() {
740                    return domain.printSize();
741            }
742    
743            /**
744             * Return a string that will give this column a default value.
745             * 
746             * @deprecated
747             */
748            public String getDefaultSetting() {
749                    return domain.getDefaultSetting();
750            }
751    
752            /**
753             * Set a string that will give this column a default value.
754             */
755            public void setDefaultValue(String def) {
756                    domain.setDefaultValue(def);
757            }
758    
759            /**
760             * Get a string that will give this column a default value.
761             */
762            public String getDefaultValue() {
763                    return domain.getDefaultValue();
764            }
765    
766            /**
767             * Returns the class name to do input validation
768             */
769            public String getInputValidator() {
770                    return this.inputValidator;
771            }
772    
773            /**
774             * Return auto increment/sequence string for the target database. We need to pass in the props for the target
775             * database!
776             */
777            public boolean isAutoIncrement() {
778                    return isAutoIncrement;
779            }
780    
781            /**
782             * Set the auto increment value. Use isAutoIncrement() to find out if it is set or not.
783             */
784            public void setAutoIncrement(boolean value) {
785                    isAutoIncrement = value;
786            }
787    
788            public String getAutoIncrementString() {
789                    if (isAutoIncrement() && IDMethod.NATIVE.equals(getTable().getIdMethod())) {
790                            return getPlatform().getAutoIncrement();
791                    }
792                    return "";
793            }
794    
795            /**
796             * Set the column type from a string property (normally a string from an sql input file)
797             */
798            public void setTypeFromString(String typeName, String size) {
799                    String tn = typeName.toUpperCase();
800                    setType(tn);
801    
802                    if (size != null) {
803                            domain.setSize(size);
804                    }
805    
806                    if (tn.indexOf("CHAR") != -1) {
807                            domain.setType(SchemaType.VARCHAR);
808                    } else if (tn.indexOf("INT") != -1) {
809                            domain.setType(SchemaType.INTEGER);
810                    } else if (tn.indexOf("FLOAT") != -1) {
811                            domain.setType(SchemaType.FLOAT);
812                    } else if (tn.indexOf("DATE") != -1) {
813                            domain.setType(SchemaType.DATE);
814                    } else if (tn.indexOf("TIME") != -1) {
815                            domain.setType(SchemaType.TIMESTAMP);
816                    } else if (tn.indexOf("BINARY") != -1) {
817                            domain.setType(SchemaType.LONGVARBINARY);
818                    } else {
819                            domain.setType(SchemaType.VARCHAR);
820                    }
821            }
822    
823            /**
824             * Return a string representation of the Java object which corresponds to the JDBC type of this column. Use in the
825             * generation of MapBuilders.
826             */
827            public String getJavaObject() {
828                    return TypeMap.getJavaObject(domain.getType());
829            }
830    
831            /**
832             * Return a string representation of the primitive java type which corresponds to the JDBC type of this column.
833             * 
834             * @return string representation of the primitive java type
835             */
836            public String getJavaPrimitive() {
837                    return TypeMap.getJavaNative(domain.getType());
838            }
839    
840            /**
841             * Return a string representation of the native java type which corresponds to the JDBC type of this column. Use in
842             * the generation of Base objects. This method is used by torque, so it returns Key types for primaryKey and
843             * foreignKey columns
844             * 
845             * @return java datatype used by torque
846             */
847            public String getJavaNative() {
848                    String jtype = TypeMap.getJavaNativeObject(domain.getType());
849                    if (isUsePrimitive()) {
850                            jtype = TypeMap.getJavaNative(domain.getType());
851                    }
852    
853                    return jtype;
854            }
855    
856            /**
857             * Return Village asX() method which corresponds to the JDBC type which represents this column.
858             */
859            public String getVillageMethod() {
860                    String vmethod = TypeMap.getVillageObjectMethod(domain.getType());
861                    if (isUsePrimitive()) {
862                            vmethod = TypeMap.getVillageMethod(domain.getType());
863                    }
864    
865                    return vmethod;
866            }
867    
868            /**
869             * Return ParameterParser getX() method which corresponds to the JDBC type which represents this column.
870             */
871            public String getParameterParserMethod() {
872                    return TypeMap.getPPMethod(domain.getType());
873            }
874    
875            /**
876             * Returns true if the column type is boolean in the java object and a numeric (1 or 0) in the db.
877             */
878            public boolean isBooleanInt() {
879                    return TypeMap.isBooleanInt(domain.getType());
880            }
881    
882            /**
883             * Returns true if the column type is boolean in the java object and a String ("Y" or "N") in the db.
884             */
885            public boolean isBooleanChar() {
886                    return TypeMap.isBooleanChar(domain.getType());
887            }
888    
889            /**
890             * Returns true if the column type is boolean in the java object and a Bit ("1" or "0") in the db.
891             */
892            public boolean isBit() {
893                    return TypeMap.isBit(domain.getType());
894            }
895    
896            /**
897             * returns true, if the columns java native type is an boolean, byte, short, int, long, float, double, char
898             */
899            public boolean isPrimitive() {
900                    String t = getJavaNative();
901                    return "boolean".equals(t) || "byte".equals(t) || "short".equals(t) || "int".equals(t) || "long".equals(t) || "float".equals(t) || "double".equals(t) || "char".equals(t);
902            }
903    
904            public boolean isUsePrimitive() {
905                    String s = getJavaType();
906                    return (s != null && s.equals("primitive")) || (s == null && !"object".equals(getTable().getDatabase().getDefaultJavaType()));
907            }
908    
909            /**
910             * @return Returns the domain.
911             */
912            public Domain getDomain() {
913                    return domain;
914            }
915    
916            /**
917             * @param domain
918             *            The domain to set.
919             */
920            public void setDomain(Domain domain) {
921                    this.domain = domain;
922            }
923    
924            private Platform getPlatform() {
925                    try {
926                            return getTable().getDatabase().getPlatform();
927                    } catch (Exception ex) {
928                            log.warn("could not load platform implementation");
929                    }
930                    return new PlatformDefaultImpl();
931            }
932    
933            public String getSqlString() {
934                    List resultList = new ArrayList();
935                    resultList.add(getName());
936    
937                    String type = getDomain().getSqlType();
938    
939                    if (getPlatform().hasSize(getDomain().getSqlType())) {
940                            type += getDomain().printSize();
941                    }
942    
943                    resultList.add(type);
944    
945                    String defaultStr = getPlatform().filterInvalidDefaultValues(getDomain().getDefaultValue());
946                    if (StringUtils.isNotEmpty(defaultStr)) {
947    
948                            resultList.add("default");
949    
950                            if (TypeMap.isTextType(getDomain().getType()) && !getPlatform().isSpecialDefault(defaultStr)) {
951                                    // TODO: Properly SQL-escape the text.
952                                    resultList.add(new StringBuffer().append('\'').append(getDefaultValue()).append('\''));
953                            } else {
954                                    resultList.add(getDefaultValue());
955                            }
956                    }
957                    if (getPlatform().createNotNullBeforeAutoincrement()) {
958                            if (StringUtils.isNotEmpty(getNotNullString())) {
959                                    resultList.add(getNotNullString());
960                            }
961                    }
962                    if (StringUtils.isNotEmpty(getAutoIncrementString())) {
963                            resultList.add(getAutoIncrementString());
964                    }
965                    if (!getPlatform().createNotNullBeforeAutoincrement()) {
966                            if (StringUtils.isNotEmpty(getNotNullString())) {
967                                    resultList.add(getNotNullString());
968                            }
969                    }
970                    return StringUtils.join(resultList.iterator(), ' ');
971            }
972    
973            /**
974             * Return the correctGetters property of the column
975             * 
976             * @return The currentValue of the correctGetters property.
977             * @since 3.2
978             */
979            public boolean isCorrectGetters() {
980                    return correctGetters;
981            }
982    
983            /**
984             * Set the correctGetters property of the column. If set to true, the column returns is&lt;xxx&gt; as the getter
985             * name which is correct for the Bean Specs but incompatible to pre-3.2 releases.
986             * 
987             * @param correctGetters
988             *            The new value of the correctGetters property.
989             * @since 3.2
990             */
991            public void setCorrectGetters(boolean correctGetters) {
992                    this.correctGetters = correctGetters;
993            }
994    
995            /**
996             * Get the value of the inheritance attribute defined in the schema XML.
997             * 
998             * @return Returns the inheritanceType.
999             */
1000            public String getInheritanceType() {
1001                    return inheritanceType;
1002            }
1003    
1004            /**
1005             * Add an XML Specified option key/value pair to this element's option set.
1006             * 
1007             * @param key
1008             *            the key of the option.
1009             * @param value
1010             *            the value of the option.
1011             */
1012            public void addOption(String key, String value) {
1013                    options.put(key, value);
1014            }
1015    
1016            /**
1017             * Get the value that was associated with this key in an XML option element.
1018             * 
1019             * @param key
1020             *            the key of the option.
1021             * @return The value for the key or a null.
1022             */
1023            public String getOption(String key) {
1024                    return (String) options.get(key);
1025            }
1026    
1027            /**
1028             * Gets the full ordered hashtable array of items specified by XML option statements under this element.
1029             * <p>
1030             * 
1031             * Note, this is not thread save but since it's only used for generation which is single threaded, there should be
1032             * minimum danger using this in Velocity.
1033             * 
1034             * @return An Map of all options. Will not be null but may be empty.
1035             */
1036            public Map getOptions() {
1037                    return options;
1038            }
1039    
1040            public int getJdbcType() {
1041                    return jdbcType;
1042            }
1043    
1044            public void setJdbcType(int jdbcType) {
1045                    this.jdbcType = jdbcType;
1046            }
1047    }