KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > hibernate > cfg > annotations > TableBinder


1 //$Id: TableBinder.java,v 1.13 2005/07/26 04:57:08 epbernard Exp $
2
package org.hibernate.cfg.annotations;
3
4 import java.util.ArrayList JavaDoc;
5 import java.util.HashMap JavaDoc;
6 import java.util.HashSet JavaDoc;
7 import java.util.Iterator JavaDoc;
8 import java.util.List JavaDoc;
9 import java.util.Map JavaDoc;
10 import java.util.Set JavaDoc;
11
12 import org.apache.commons.logging.Log;
13 import org.apache.commons.logging.LogFactory;
14 import org.hibernate.AnnotationException;
15 import org.hibernate.AssertionFailure;
16 import org.hibernate.annotations.Index;
17 import org.hibernate.cfg.AnnotationBinder;
18 import org.hibernate.cfg.Ejb3JoinColumn;
19 import org.hibernate.cfg.ExtendedMappings;
20 import org.hibernate.mapping.Collection;
21 import org.hibernate.mapping.Column;
22 import org.hibernate.mapping.DependantValue;
23 import org.hibernate.mapping.PersistentClass;
24 import org.hibernate.mapping.Property;
25 import org.hibernate.mapping.SimpleValue;
26 import org.hibernate.mapping.Table;
27 import org.hibernate.mapping.ToOne;
28 import org.hibernate.mapping.Value;
29 import org.hibernate.util.StringHelper;
30
31 /**
32  * Table related operations
33  * @author Emmanuel Bernard
34  */

35 public abstract class TableBinder {
36     //TODO move it to a getter/setter strategy
37
private static Log log = LogFactory.getLog(TableBinder.class);
38
39     public static Table fillTable(
40             String JavaDoc schema, String JavaDoc catalog, String JavaDoc realTableName, boolean isAbstract,
41             List JavaDoc uniqueConstraints, String JavaDoc constraints, Table denormalizedSuperTable, ExtendedMappings mappings
42             ) {
43         schema = AnnotationBinder.isDefault(schema) ? schema = mappings.getSchemaName() : schema;
44         catalog = AnnotationBinder.isDefault(catalog) ? catalog = mappings.getCatalogName() : catalog;
45         Table table;
46         if (denormalizedSuperTable != null) {
47             table = mappings.addDenormalizedTable(
48                 schema,
49                 catalog,
50                 realTableName,
51                 isAbstract,
52                 null, //subselect
53
denormalizedSuperTable
54             );
55         }
56         else {
57             table = mappings.addTable(
58                 schema,
59                 catalog,
60                 realTableName,
61                 null, //subselect
62
isAbstract
63             );
64         }
65         if (uniqueConstraints != null && uniqueConstraints.size() > 0)
66             mappings.addUniqueConstraints(table, uniqueConstraints);
67         if (constraints != null) table.addCheckConstraint(constraints);
68         return table;
69     }
70
71     /**
72      * bind the inverse FK of a ManyToMany
73      * If we are in a mappedBy case, read the columns from the associated
74      * colletion element
75      * Otherwise delegates to the usual algorithm
76      */

77     public static void bindManytoManyInverseFk(
78             PersistentClass referencedEntity, Ejb3JoinColumn[] columns, SimpleValue value, boolean unique,
79             ExtendedMappings mappings
80             ) {
81         if ( ! StringHelper.isEmpty( columns[0].getMappedBy() ) ) {
82             final Property property = referencedEntity.getProperty( columns[0].getMappedBy() );
83             Iterator JavaDoc mappedByColumns = ( (Collection) property.getValue() ).getKey().getColumnIterator();
84             while ( mappedByColumns.hasNext() ) {
85                 Column column = (Column) mappedByColumns.next();
86                 columns[0].linkValueUsingAColumnCopy(column, value);
87             }
88             value.createForeignKey();
89         }
90         else {
91             bindFk(referencedEntity, null, columns, value, unique );
92         }
93     }
94
95     public static void bindFk(
96             PersistentClass referencedEntity, PersistentClass destinationEntity, Ejb3JoinColumn[] columns, SimpleValue value,
97             boolean unique
98             ) {
99         PersistentClass associatedClass;
100         if (destinationEntity != null) {
101             //overidden destination
102
associatedClass = destinationEntity;
103         }
104         else {
105             associatedClass = columns[0].getPropertyHolder() == null ? null : columns[0].getPropertyHolder().getPersistentClass();
106         }
107         final String JavaDoc mappedByProperty = columns[0].getMappedBy();
108         if ( ! StringHelper.isEmpty( mappedByProperty ) ) {
109             /**
110              * Get the columns of the mapped-by property
111              * copy them and link the copy to the actual value
112              */

113             if ( log.isDebugEnabled() ) log.debug("Retrieving property " + associatedClass.getEntityName() + "." + mappedByProperty );
114
115             final Property property = associatedClass.getProperty( columns[0].getMappedBy() );
116             Iterator JavaDoc mappedByColumns;
117             if ( property.getValue() instanceof Collection) {
118                 mappedByColumns = ( (Collection) property.getValue() ).getElement().getColumnIterator();
119             }
120             else {
121                 mappedByColumns = property.getValue().getColumnIterator();
122             }
123             while ( mappedByColumns.hasNext() ) {
124                 Column column = (Column) mappedByColumns.next();
125                 columns[0].linkValueUsingAColumnCopy(column, value);
126             }
127         } else if ( columns[0].isImplicit() ) {
128             /**
129              * if columns are implicit, then create the columns based on the
130              * referenced entity id columns
131              */

132             Iterator JavaDoc idColumns = referencedEntity.getIdentifier().getColumnIterator();
133             while ( idColumns.hasNext() ) {
134                 Column column = (Column) idColumns.next();
135                 columns[0].linkValueUsingDefaultColumnNaming(column, value);
136             }
137         }
138         else {
139             int fkEnum = Ejb3JoinColumn.checkReferencedColumnsType(columns, referencedEntity);
140
141             if ( Ejb3JoinColumn.NON_PK_REFERENCE == fkEnum ) {
142                 String JavaDoc referencedPropertyName;
143                 if (value instanceof ToOne) {
144                     referencedPropertyName = ( (ToOne) value ).getReferencedPropertyName();
145                 }
146                 else if (value instanceof DependantValue) {
147                     Collection collection = (Collection) referencedEntity.getProperty( columns[0].getPropertyName() ).getValue();
148                     referencedPropertyName = collection.getReferencedPropertyName();
149                 }
150                 else {
151                     throw new AssertionFailure("Do a property ref on an unexpected Value type: "
152                             + value.getClass().getName() );
153                 }
154                 if (referencedPropertyName == null) throw new AssertionFailure("No property ref found while expected");
155                 Property synthProp = referencedEntity.getProperty( referencedPropertyName );
156                 if (synthProp == null) throw new AssertionFailure("Cannot find synthProp: " + referencedEntity.getEntityName() + "." + referencedPropertyName );
157                 linkColumnWithValueOverridingNameIfImplicit( synthProp.getColumnIterator(), columns, value );
158
159             }
160             else {
161                 if ( Ejb3JoinColumn.NO_REFERENCE == fkEnum ) {
162                     //implicit case, we hope PK and FK columns are in the same order
163
if (columns.length != referencedEntity.getIdentifier().getColumnSpan() ) {
164                         throw new AnnotationException("A Foreign key refering " + referencedEntity.getEntityName()
165                             + " has the wrong number of column. should be " + referencedEntity.getIdentifier().getColumnSpan()
166                         );
167                     }
168                     //Iterator idColumnsIt = referencedEntity.getIdentifier().getColumnIterator();
169
linkColumnWithValueOverridingNameIfImplicit(
170                             referencedEntity.getIdentifier().getColumnIterator(),
171                             columns,
172                             value
173                     );
174                 }
175                 else {
176                     //explicit referencedColumnName
177
Iterator JavaDoc idColItr = referencedEntity.getIdentifier().getColumnIterator();
178                     org.hibernate.mapping.Column col;
179                     if (! idColItr.hasNext()) log.debug("No column in the identifier!");
180                     while ( idColItr.hasNext() ) {
181                         boolean match = false;
182                         //for each PK column, find the associated FK column.
183
col = (org.hibernate.mapping.Column) idColItr.next();
184                         for (Ejb3JoinColumn joinCol : columns) {
185                             if ( joinCol.getReferencedColumn().equals( col.getName() ) ) {
186                                 //proper join column
187
if ( joinCol.isNameDeferred() ) {
188                                     joinCol.redefineColumnName( joinCol.getPropertyName() + "_" + joinCol.getReferencedColumn() );
189                                 }
190                                 joinCol.linkWithValue(value);
191                                 match = true;
192                                 break;
193                             }
194                         }
195                         if (match == false) {
196                             throw new AnnotationException("Column name " + col.getName() + " of "
197                                     + referencedEntity.getEntityName() + " not found in JoinColumns.referencedColumnName");
198                         }
199                     }
200                 }
201             }
202         }
203
204 // OLD original code
205
// if (referencedEntity.getIdentifier().getColumnSpan() == 1) {
206
// if (columns.length != 1) {
207
// throw new AnnotationException("@JoinColumns with " + columns.length + " columns"
208
// + " refers to " + referencedEntity.getEntityName() + " which has a "
209
// + referencedEntity.getIdentifier().getColumnSpan() + " sized PK");
210
// }
211
// else {
212
// if ( columns[0].isNameDeferred() ) {
213
// //this has to be the default value
214
// Column idCol = (Column) referencedEntity.getIdentifier().getColumnIterator().next();
215
// columns[0].redefineColumnName( columns[0].getPropertyName() + "_" + idCol.getName() );
216
// }
217
// columns[0].linkWithValue(value);
218
// }
219
// }
220
// else {
221
// //Check if we have to do it the implicit way
222
// //TODO: clarify the spec on it
223
// boolean noReferencedColumn = true;
224
// for (Ejb3JoinColumn joinCol : columns) {
225
// if ( StringHelper.isNotEmpty( joinCol.getReferencedColumn() ) ) {
226
// noReferencedColumn = false;
227
// break;
228
// }
229
//
230
// }
231
// if (noReferencedColumn) {
232
// //implicit case, we hope PK and FK columns are in the same order
233
// if (columns.length != referencedEntity.getIdentifier().getColumnSpan() ) {
234
// throw new AnnotationException("A Foreign key refering " + referencedEntity.getEntityName()
235
// + " has the wrong number of column. should be " + referencedEntity.getIdentifier().getColumnSpan()
236
// );
237
// }
238
// idColumnsIt = referencedEntity.getIdentifier().getColumnIterator();
239
// for (Ejb3JoinColumn joinCol : columns) {
240
// Column idCol = (Column) idColumnsIt.next();
241
// if ( joinCol.isNameDeferred() ) {
242
// //this has to be the default value
243
// joinCol.redefineColumnName( joinCol.getPropertyName() + "_" + idCol.getName() );
244
// }
245
// joinCol.linkWithValue(value);
246
// }
247
// }
248
// else {
249
// //explicit referencedColumnName
250
// Iterator idColItr = referencedEntity.getIdentifier().getColumnIterator();
251
// org.hibernate.mapping.Column col;
252
// if (! idColItr.hasNext()) log.debug("No column in the identifier!");
253
// while ( idColItr.hasNext() ) {
254
// boolean match = false;
255
// //for each PK column, find the associated FK column.
256
// col = (org.hibernate.mapping.Column) idColItr.next();
257
// for (Ejb3JoinColumn joinCol : columns) {
258
// if ( joinCol.getReferencedColumn().equals( col.getName() ) ) {
259
// //proper join column
260
// if ( joinCol.isNameDeferred() ) {
261
// joinCol.redefineColumnName( joinCol.getPropertyName() + "_" + joinCol.getReferencedColumn() );
262
// }
263
// joinCol.linkWithValue(value);
264
// match = true;
265
// break;
266
// }
267
// }
268
// if (match == false) {
269
// throw new AnnotationException("Column name " + col.getName() + " of "
270
// + referencedEntity.getEntityName() + " not found in JoinColumns.referencedColumnName");
271
// }
272
// }
273
// }
274
// }
275
// }
276
value.createForeignKey();
277         if ( unique == true ) {
278             createUniqueConstraint( value );
279         }
280     }
281
282     private static void linkColumnWithValueOverridingNameIfImplicit(Iterator JavaDoc columnIterator, Ejb3JoinColumn[] columns, SimpleValue value) {
283         for (Ejb3JoinColumn joinCol : columns) {
284             Column synthCol = (Column) columnIterator.next();
285             if ( joinCol.isNameDeferred() ) {
286                 //this has to be the default value
287
joinCol.redefineColumnName( joinCol.getPropertyName() + "_" + synthCol.getName() );
288             }
289             joinCol.linkWithValue(value);
290         }
291     }
292
293     public static void createUniqueConstraint(Value value) {
294         Iterator JavaDoc iter = value.getColumnIterator();
295         ArrayList JavaDoc cols = new ArrayList JavaDoc();
296         while ( iter.hasNext() ) {
297             cols.add( iter.next() );
298         }
299         value.getTable().createUniqueKey( cols );
300     }
301
302     private static List JavaDoc<Property> findPropertiesByColumns(PersistentClass referencedEntity, Ejb3JoinColumn[] columns) {
303         Map JavaDoc<Column,Set JavaDoc<Property>> columnsToProperty = new HashMap JavaDoc<Column,Set JavaDoc<Property>>();
304         List JavaDoc<Column> orderedColumns = new ArrayList JavaDoc<Column>();
305         for(int index = 0 ; index < columns.length ; index++) {
306             Column column = new Column( columns[index].getReferencedColumn() );
307             orderedColumns.add( column );
308             columnsToProperty.put( column, new HashSet JavaDoc<Property>() );
309         }
310         Iterator JavaDoc it = referencedEntity.getPropertyIterator();
311         while ( it.hasNext() ) {
312             Property property = (Property) it.next();
313             Iterator JavaDoc columnIt = property.getColumnIterator();
314             while ( columnIt.hasNext() ) {
315                 Column column = (Column) columnIt.next();
316                 if ( columnsToProperty.containsKey( column ) ) {
317                     columnsToProperty.get( column ).add( property );
318                 }
319             }
320         }
321         //first naive implementation
322
//only check 1 columns properties
323
//TODO make it smarter by checking correctly ordered multi column properties
324
List JavaDoc<Property> orderedProperties = new ArrayList JavaDoc<Property>();
325         for (Column column : orderedColumns) {
326             boolean found = false;
327             for (Property property : columnsToProperty.get( column ) ) {
328                 if (property.getColumnSpan() == 1) {
329                     orderedProperties.add(property);
330                     found = true;
331                     break;
332                 }
333             }
334             if (!found) return null; //have to find it the hard way
335
}
336         return orderedProperties;
337     }
338
339     public static void addIndexes(Table hibTable, Index[] indexes) {
340         for ( Index index : indexes ) {
341             String JavaDoc indexName = index.name();
342             for ( String JavaDoc columnName : index.columnNames() ) {
343                 Column column = hibTable.getColumn( new Column(columnName) );
344                 if (column == null) throw new AnnotationException( "@Index references a unknown column: " + columnName );
345                 hibTable.getOrCreateIndex( indexName ).addColumn( column );
346             }
347         }
348     }
349 }
350
Popular Tags