KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > hibernate > cfg > Ejb3Column


1 //$Id: Ejb3Column.java,v 1.26 2005/07/26 04:57:09 epbernard Exp $
2
package org.hibernate.cfg;
3
4 import java.util.Map JavaDoc;
5
6 import org.apache.commons.logging.Log;
7 import org.apache.commons.logging.LogFactory;
8 import org.hibernate.AnnotationException;
9 import org.hibernate.AssertionFailure;
10 import org.hibernate.annotations.Index;
11 import org.hibernate.cfg.annotations.Nullability;
12 import org.hibernate.mapping.Column;
13 import org.hibernate.mapping.Join;
14 import org.hibernate.mapping.Property;
15 import org.hibernate.mapping.SimpleValue;
16 import org.hibernate.mapping.Table;
17 import org.hibernate.mapping.Formula;
18 import org.hibernate.util.StringHelper;
19
20 /**
21  * Wrap state of an EJB3 @Column annotation
22  * and build the Hibernate column mapping element
23  *
24  * @author Emmanuel Bernard
25  */

26 public class Ejb3Column {
27     private static final Log log = LogFactory.getLog(Ejb3Column.class);
28     private Column mappingColumn;
29     private boolean insertable = true;
30     private boolean updatable = true;
31     private String JavaDoc secondaryTableName;
32     protected Map JavaDoc<String JavaDoc, Join> joins;
33     protected PropertyHolder propertyHolder;
34     private Mappings mappings;
35     private boolean isImplicit;
36     public static final int DEFAULT_COLUMN_LENGTH = 255;
37     public String JavaDoc sqlType;
38     private int length = DEFAULT_COLUMN_LENGTH;
39     private int precision;
40     private int scale;
41     private String JavaDoc columnName;
42     private boolean unique;
43     private boolean nullable = true;
44     private String JavaDoc formulaString;
45     private Formula formula;
46
47     public String JavaDoc getSqlType() {
48         return sqlType;
49     }
50
51     public int getLength() {
52         return length;
53     }
54
55     public int getPrecision() {
56         return precision;
57     }
58
59     public int getScale() {
60         return scale;
61     }
62
63     public boolean isUnique() {
64         return unique;
65     }
66
67     public String JavaDoc getFormulaString() {
68         return formulaString;
69     }
70
71     public String JavaDoc getSecondaryTableName() {
72         return secondaryTableName;
73     }
74
75     public void setFormula(String JavaDoc formula) {
76         this.formulaString = formula;
77     }
78
79     public boolean isImplicit() {
80         return isImplicit;
81     }
82
83     public void setInsertable(boolean insertable) {
84         this.insertable = insertable;
85     }
86
87     public void setUpdatable(boolean updatable) {
88         this.updatable = updatable;
89     }
90
91     public void setMappings(Mappings mappings) {
92         this.mappings = mappings;
93     }
94
95     public void setImplicit(boolean implicit) {
96         isImplicit = implicit;
97     }
98
99     public void setSqlType(String JavaDoc sqlType) {
100         this.sqlType = sqlType;
101     }
102
103     public void setLength(int length) {
104         this.length = length;
105     }
106
107     public void setPrecision(int precision) {
108         this.precision = precision;
109     }
110
111     public void setScale(int scale) {
112         this.scale = scale;
113     }
114
115     public void setColumnName(String JavaDoc columnName) {
116         this.columnName = columnName;
117     }
118
119     public void setUnique(boolean unique) {
120         this.unique = unique;
121     }
122
123     public boolean isNullable() {
124         return mappingColumn.isNullable();
125     }
126
127     public Ejb3Column() {}
128
129     public void bind() {
130         if ( StringHelper.isNotEmpty(formulaString) ) {
131             log.debug("binding formula " + formulaString);
132             formula = new Formula();
133             formula.setFormula(formulaString);
134         }
135         else {
136             log.debug("Binding column " + columnName + " unique " + unique);
137             initMappingColumn(columnName, length, precision, scale, nullable, sqlType, unique);
138         }
139     }
140
141     protected void initMappingColumn(String JavaDoc name, int length, int precision, int scale, boolean nullable, String JavaDoc sqlType, boolean unique) {
142         this.mappingColumn = new Column();
143         redefineColumnName(name);
144         this.mappingColumn.setLength(length);
145         if (precision > 0) { //revelent precision
146
this.mappingColumn.setPrecision(precision);
147             this.mappingColumn.setScale(scale);
148         }
149         this.mappingColumn.setNullable(nullable);
150         this.mappingColumn.setSqlType(sqlType);
151         this.mappingColumn.setUnique(unique);
152     }
153
154     public boolean isNameDeferred() {
155         return mappingColumn == null || StringHelper.isEmpty( mappingColumn.getName() );
156     }
157
158     public void redefineColumnName(String JavaDoc name) {
159         if (name != null) {
160             mappingColumn.setName( mappings.getNamingStrategy().columnName( name ) );
161         }
162     }
163
164     public String JavaDoc getName() {
165         return mappingColumn.getName();
166     }
167
168     public Column getMappingColumn() {
169         return mappingColumn;
170     }
171
172     public boolean isInsertable() {
173         return insertable;
174     }
175
176     public boolean isUpdatable() {
177         return updatable;
178     }
179
180     public void setNullable(boolean nullable) {
181         if ( mappingColumn != null ) {
182             mappingColumn.setNullable(nullable);
183         }
184         else {
185             this.nullable = nullable;
186         }
187     }
188
189     public void setJoins(Map JavaDoc<String JavaDoc, Join> joins) {
190         this.joins = joins;
191     }
192
193     public PropertyHolder getPropertyHolder() {
194         return propertyHolder;
195     }
196
197     public void setPropertyHolder(PropertyHolder propertyHolder) {
198         this.propertyHolder = propertyHolder;
199     }
200
201     protected void setMappingColumn(Column mappingColumn) {
202         this.mappingColumn = mappingColumn;
203     }
204
205     public void linkWithValue(SimpleValue value) {
206         if ( formula != null ) {
207             value.addFormula(formula);
208         }
209         else {
210             getMappingColumn().setValue(value);
211             value.addColumn( getMappingColumn() );
212             value.getTable().addColumn( getMappingColumn() );
213         }
214     }
215     /**
216      * Find appropriate table of the column.
217      * It can come from a secondary table or from the main table of the persistent class
218      *
219      * @return appropriate table
220      * @exception AnnotationException missing secondary table
221      */

222     public Table getTable() {
223         
224         if ( isSecondary() ) {
225             return getJoin().getTable();
226         }
227         else {
228             return propertyHolder.getTable();
229         }
230     }
231     
232     public boolean isSecondary() {
233         if (propertyHolder == null) {
234             throw new AssertionFailure("Should not call getTable() on column wo persistent class defined");
235         }
236         if ( StringHelper.isNotEmpty(secondaryTableName) ) {
237             return true;
238         }
239         // else {
240
return false;
241     }
242
243     private Join getJoin() {
244         Join join = joins.get(secondaryTableName);
245         if (join == null) {
246             throw new AnnotationException("Cannot find the expected secondary table: no "
247                 + secondaryTableName + " in " + propertyHolder.getClassName() );
248         }
249         else {
250             return join;
251         }
252     }
253     
254     /**
255      * Add a property to either the persistent class or the
256      * join stuff.
257      * FIXME: this should *not* be here because we mix contexts,
258      * but thats the easiest way for now
259      */

260     public void addPropertyToMappingContainer(Property prop) {
261         if ( isSecondary() ) {
262             getJoin().addProperty(prop);
263         }
264         else {
265             propertyHolder.addProperty(prop);
266         }
267     }
268
269     public void forceNotNull() {
270          mappingColumn.setNullable(false);
271     }
272
273     public void setSecondaryTableName(String JavaDoc secondaryTableName) {
274         this.secondaryTableName = secondaryTableName;
275     }
276
277     public static Ejb3Column[] buildColumnFromAnnotation(
278             javax.persistence.Column[] anns,
279             org.hibernate.annotations.Formula formulaAnn, Nullability nullability, PropertyHolder propertyHolder,
280             PropertyInferredData inferredData,
281             Map JavaDoc<String JavaDoc, Join> secondaryTables,
282             ExtendedMappings mappings
283             ) {
284         Ejb3Column[] columns;
285         if (formulaAnn != null) {
286             Ejb3Column formulaColumn = new Ejb3Column();
287             formulaColumn.setFormula( formulaAnn.value() );
288             formulaColumn.setImplicit(false);
289             formulaColumn.setMappings(mappings);
290             formulaColumn.setPropertyHolder(propertyHolder);
291             formulaColumn.bind();
292             columns = new Ejb3Column[] { formulaColumn };
293         }
294         else {
295             javax.persistence.Column[] actualCols = anns;
296             javax.persistence.Column[] overriddenCols = propertyHolder.getOverriddenColumn( inferredData.getPropertyName() );
297             if (overriddenCols != null) {
298                 //check for overridden first
299
if (anns != null && overriddenCols.length != anns.length) {
300                     throw new AnnotationException("AttributeOverride.column() should override all columns for now");
301                 }
302                 actualCols = overriddenCols.length == 0 ? null : overriddenCols;
303                 log.debug( "Column(s) overridden for property " + inferredData.getPropertyName() );
304             }
305             if (actualCols == null) {
306                 columns = buildImplicitColumn(inferredData, secondaryTables, propertyHolder, nullability, mappings);
307             }
308             else {
309                 final int length = actualCols.length;
310                 columns = new Ejb3Column[length];
311                 for (int index = 0 ; index < length ; index++) {
312                     javax.persistence.Column col = actualCols[index];
313                     String JavaDoc sqlType = col.columnDefinition().equals("") ? null : col.columnDefinition();
314                     String JavaDoc name = col.name().equals("") ? inferredData.getPropertyName() : col.name();
315                     Ejb3Column column = new Ejb3Column();
316                     column.setImplicit(false);
317                     column.setSqlType(sqlType);
318                     column.setLength( col.length() );
319                     column.setPrecision( col.precision() );
320                     column.setScale( col.scale() );
321                     column.setColumnName(name);
322                     column.setNullable( col.nullable() ); //TODO force to not null if available? This is a (bad) user choice.
323
column.setUnique( col.unique() );
324                     column.setInsertable( col.insertable() );
325                     column.setUpdatable( col.updatable() );
326                     column.setSecondaryTableName( col.secondaryTable() );
327                     column.setPropertyHolder(propertyHolder);
328                     column.setJoins(secondaryTables);
329                     column.setMappings(mappings);
330                     column.bind();
331                     columns[index] = column;
332                 }
333             }
334         }
335         return columns;
336     }
337
338     private static Ejb3Column[] buildImplicitColumn(
339             PropertyInferredData inferredData, Map JavaDoc<String JavaDoc, Join> secondaryTables, PropertyHolder propertyHolder,
340             Nullability nullability, ExtendedMappings mappings
341             ) {
342         Ejb3Column[] columns;
343         columns = new Ejb3Column[1];
344         Ejb3Column column = new Ejb3Column();
345         column.setImplicit(false);
346         //not following the spec but more clean
347
if ( nullability != Nullability.FORCED_NULL
348                 && inferredData.getReturnedClassOrElement().isPrimitive()
349                 && ! inferredData.isArray() ) {
350             column.setNullable(false);
351         }
352         column.setLength( DEFAULT_COLUMN_LENGTH );
353         column.setColumnName( inferredData.getPropertyName() );
354         column.setPropertyHolder(propertyHolder);
355         column.setJoins(secondaryTables);
356         column.setMappings(mappings);
357         column.bind();
358         columns[0] = column;
359         return columns;
360     }
361
362     public static void checkPropertyConsistency(Ejb3Column[] columns, String JavaDoc propertyName) {
363         int nbrOfColumns = columns.length;
364         if (nbrOfColumns > 1) {
365             for (int currentIndex = 1 ; currentIndex < nbrOfColumns ; currentIndex++) {
366                 if ( columns[currentIndex].isInsertable() != columns[currentIndex-1].isInsertable() ) {
367                     throw new AnnotationException( "Mixing insertable and non insertable columns in a property is not allowed: " + propertyName );
368                 }
369                 if ( columns[currentIndex].isNullable() != columns[currentIndex-1].isNullable() ) {
370                     throw new AnnotationException( "Mixing nullable and non nullable columns in a property is not allowed: " + propertyName );
371                 }
372                 if ( columns[currentIndex].isUpdatable() != columns[currentIndex-1].isUpdatable() ) {
373                     throw new AnnotationException( "Mixing updatable and non updatable columns in a property is not allowed: " + propertyName );
374                 }
375                 if ( ! columns[currentIndex].getTable().equals( columns[currentIndex-1].getTable() ) ) {
376                     throw new AnnotationException( "Mixing different tables in a property is not allowed: " + propertyName );
377                 }
378             }
379         }
380     }
381
382     public void addIndex(Index index) {
383         if (index == null) return;
384         if (mappingColumn == null) {
385             throw new AnnotationException( "Index on formula not allowed: " + propertyHolder.getEntityName() );
386         }
387         if ( StringHelper.isEmpty( secondaryTableName ) ) {
388             propertyHolder.getPersistentClass().getRootTable().getOrCreateIndex( index.name() ).addColumn( mappingColumn );
389         }
390         else {
391             getJoin().getTable().getOrCreateIndex( index.name() ).addColumn( mappingColumn );
392         }
393     }
394 }
Popular Tags