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