KickJava   Java API By Example, From Geeks To Geeks.

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


1 //$Id: EntityBinder.java,v 1.25 2005/07/26 04:57:08 epbernard Exp $
2
package org.hibernate.cfg.annotations;
3
4 import java.lang.reflect.Modifier JavaDoc;
5 import java.util.ArrayList JavaDoc;
6 import java.util.HashMap JavaDoc;
7 import java.util.Iterator JavaDoc;
8 import java.util.List JavaDoc;
9 import java.util.Map JavaDoc;
10 import javax.persistence.AccessType;
11 import javax.persistence.Entity;
12 import javax.persistence.JoinColumn;
13 import javax.persistence.JoinColumns;
14 import javax.persistence.SecondaryTable;
15 import javax.persistence.SecondaryTables;
16 import javax.persistence.UniqueConstraint;
17
18 import org.apache.commons.logging.Log;
19 import org.apache.commons.logging.LogFactory;
20 import org.hibernate.AnnotationException;
21 import org.hibernate.AssertionFailure;
22 import org.hibernate.MappingException;
23 import org.hibernate.annotations.BatchSize;
24 import org.hibernate.annotations.Cache;
25 import org.hibernate.annotations.CacheConcurrencyStrategy;
26 import org.hibernate.annotations.OptimisticLockType;
27 import org.hibernate.annotations.PolymorphismType;
28 import org.hibernate.annotations.Proxy;
29 import org.hibernate.annotations.Tables;
30 import org.hibernate.annotations.Where;
31 import org.hibernate.cache.CacheFactory;
32 import org.hibernate.cfg.AnnotationBinder;
33 import org.hibernate.cfg.Ejb3JoinColumn;
34 import org.hibernate.cfg.ExtendedMappings;
35 import org.hibernate.cfg.InheritanceState;
36 import org.hibernate.cfg.PropertyHolder;
37 import org.hibernate.engine.Versioning;
38 import org.hibernate.mapping.DependantValue;
39 import org.hibernate.mapping.Join;
40 import org.hibernate.mapping.PersistentClass;
41 import org.hibernate.mapping.RootClass;
42 import org.hibernate.mapping.SimpleValue;
43 import org.hibernate.mapping.Table;
44 import org.hibernate.mapping.TableOwner;
45 import org.hibernate.util.ReflectHelper;
46 import org.hibernate.util.StringHelper;
47
48 /**
49  * Stateful holder and processor for binding Entity information
50  *
51  * @author Emmanuel Bernard
52  */

53 public class EntityBinder {
54     private String JavaDoc name;
55     private Class JavaDoc annotatedClass;
56     private PersistentClass persistentClass;
57     private ExtendedMappings mappings;
58     private static Log log = LogFactory.getLog(EntityBinder.class);
59     private String JavaDoc discriminatorValue = "";
60     private boolean propertyAccess = false;
61     private boolean dynamicInsert;
62     private boolean dynamicUpdate;
63     private boolean mutable;
64     private OptimisticLockType optimisticLockType;
65     private String JavaDoc persister;
66     private PolymorphismType polymorphismType;
67     private boolean selectBeforeUpdate;
68     private int batchSize;
69     private boolean lazy;
70     private String JavaDoc proxyClassName;
71     private String JavaDoc where;
72     private java.util.Map JavaDoc<String JavaDoc, Join> secondaryTables = new HashMap JavaDoc<String JavaDoc, Join>();
73     private java.util.Map JavaDoc<String JavaDoc, Object JavaDoc> secondaryTableJoins = new HashMap JavaDoc<String JavaDoc, Object JavaDoc>();
74     private String JavaDoc cacheConcurrentStrategy;
75     private String JavaDoc cacheRegion;
76     private java.util.Map JavaDoc<String JavaDoc,String JavaDoc> filters = new HashMap JavaDoc<String JavaDoc, String JavaDoc>();
77     private InheritanceState inheritanceState;
78     private boolean ignoreIdAnnotations;
79
80     public boolean isPropertyAccess() {
81         return propertyAccess;
82     }
83
84     public EntityBinder(Entity ejb3Ann, org.hibernate.annotations.Entity hibAnn,
85                         Class JavaDoc annotatedClass, PersistentClass persistentClass,
86                         ExtendedMappings mappings) {
87         this.mappings = mappings;
88         this.persistentClass = persistentClass;
89         this.annotatedClass = annotatedClass;
90         bindEjb3Annotation(ejb3Ann);
91         bindHibernateAnnotation(hibAnn);
92     }
93
94     private void bindHibernateAnnotation(org.hibernate.annotations.Entity hibAnn) {
95         if (hibAnn != null) {
96             dynamicInsert = hibAnn.dynamicInsert();
97             dynamicUpdate = hibAnn.dynamicUpdate();
98             mutable = hibAnn.mutable();
99             optimisticLockType = hibAnn.optimisticLock();
100             persister = hibAnn.persister();
101             selectBeforeUpdate = hibAnn.selectBeforeUpdate();
102             polymorphismType = hibAnn.polymorphism();
103         }
104         else {
105             //default values when the annotation is not there
106
dynamicInsert = false;
107             dynamicUpdate = false;
108             mutable = true;
109             optimisticLockType = OptimisticLockType.VERSION;
110             persister = "";
111             polymorphismType = PolymorphismType.IMPLICIT;
112             selectBeforeUpdate = false;
113         }
114     }
115
116     private void bindEjb3Annotation(Entity ejb3Ann) {
117         if (ejb3Ann == null) throw new AssertionFailure("@Entity should always be not null");
118         if ( AnnotationBinder.isDefault( ejb3Ann.name() ) ) {
119             name = StringHelper.unqualify( annotatedClass.getName() );
120         }
121         else {
122             name = ejb3Ann.name();
123         }
124         propertyAccess = ejb3Ann.access() == AccessType.PROPERTY;
125     }
126
127     public void setDiscriminatorValue(String JavaDoc discriminatorValue) {
128         this.discriminatorValue = discriminatorValue;
129     }
130
131     public void bindEntity() {
132         persistentClass.setAbstract( Modifier.isAbstract( annotatedClass.getModifiers() ) );
133         persistentClass.setClassName( annotatedClass.getName() );
134         //persistentClass.setDynamic(false); //no longer needed with the Entity name refactoring?
135
persistentClass.setEntityName( annotatedClass.getName() );
136         if ( StringHelper.isEmpty( discriminatorValue ) ) {
137             persistentClass.setDiscriminatorValue( persistentClass.getEntityName() );
138         }
139         else {
140             persistentClass.setDiscriminatorValue(discriminatorValue);
141         }
142
143         persistentClass.setLazy(lazy);
144         if (! StringHelper.isEmpty(proxyClassName) ) {
145             persistentClass.setProxyInterfaceName(proxyClassName);
146         }
147         persistentClass.setDynamicInsert(dynamicInsert);
148         persistentClass.setDynamicUpdate(dynamicUpdate);
149         if (persistentClass instanceof RootClass) {
150             RootClass rootClass = (RootClass) persistentClass;
151             rootClass.setMutable(mutable);
152             rootClass.setExplicitPolymorphism( isExplicitPolymorphism(polymorphismType) );
153             if ( StringHelper.isNotEmpty(where) ) rootClass.setWhere(where);
154             if ( cacheConcurrentStrategy != null) {
155                 rootClass.setCacheConcurrencyStrategy(cacheConcurrentStrategy);
156                 rootClass.setCacheRegionName(cacheRegion);
157             }
158         }
159         persistentClass.setOptimisticLockMode( getVersioning(optimisticLockType) );
160         persistentClass.setSelectBeforeUpdate(selectBeforeUpdate);
161         if (! AnnotationBinder.isDefault(persister) ) {
162             try {
163                 persistentClass.setEntityPersisterClass( ReflectHelper.classForName(persister) );
164             }
165             catch ( ClassNotFoundException JavaDoc cnfe ) {
166                 throw new AnnotationException("Could not find persister class: " + persister);
167             }
168         }
169         persistentClass.setBatchSize(batchSize);
170
171         if (! inheritanceState.hasParents) {
172             Iterator JavaDoc<Map.Entry JavaDoc<String JavaDoc,String JavaDoc>> iter = filters.entrySet().iterator();
173             while ( iter.hasNext() ) {
174                 Map.Entry JavaDoc<String JavaDoc,String JavaDoc> filter = iter.next();
175                 persistentClass.addFilter( filter.getKey(), filter.getValue() );
176             }
177         }
178         else {
179             if ( filters.size() > 0)
180                 log.warn("@Filter not allowed on subclasses (ignored): " + persistentClass.getEntityName() );
181         }
182         log.debug("Import with entity name=" + name);
183         try {
184             mappings.addImport(persistentClass.getEntityName(), name);
185         }
186         catch (MappingException me) {
187             throw new AnnotationException("Use of the same entity name twice: " + name);
188         }
189     }
190
191     int getVersioning(OptimisticLockType type) {
192         switch(type) {
193             case VERSION:
194                 return Versioning.OPTIMISTIC_LOCK_VERSION;
195             case NONE:
196                 return Versioning.OPTIMISTIC_LOCK_NONE;
197             case DIRTY:
198                 return Versioning.OPTIMISTIC_LOCK_DIRTY;
199             case ALL:
200                 return Versioning.OPTIMISTIC_LOCK_ALL;
201             default:
202                 throw new AssertionFailure("optimistic locking not supported: " + type);
203         }
204     }
205
206     private boolean isExplicitPolymorphism(PolymorphismType type) {
207         switch(type) {
208             case IMPLICIT:
209                 return false;
210             case EXPLICIT:
211                 return true;
212             default:
213                 throw new AssertionFailure("Unknown polymorphism type: " + type);
214         }
215     }
216
217     public void setBatchSize(BatchSize sizeAnn) {
218         if (sizeAnn != null) {
219             batchSize = sizeAnn.size();
220         }
221         else {
222             batchSize = -1;
223         }
224     }
225
226     public void setProxy(Proxy proxy) {
227         if (proxy != null) {
228             lazy = proxy.lazy();
229             if (!lazy) {
230                 proxyClassName = null;
231             }
232             else {
233                 if ( AnnotationBinder.isDefault( proxy.proxyClassName() ) ) {
234                     proxyClassName = annotatedClass.getName();
235                 }
236                 else {
237                     proxyClassName = proxy.proxyClassName();
238                 }
239             }
240         }
241         else {
242             lazy = true; //needed to allow association lazy loading.
243
proxyClassName = annotatedClass.getName();
244         }
245     }
246
247     public void setWhere(Where whereAnn) {
248         if (whereAnn != null) {
249             where = whereAnn.clause();
250         }
251     }
252
253     private String JavaDoc getClassTableName(String JavaDoc tableName) {
254         if ( StringHelper.isEmpty(tableName) ) {
255             return mappings.getNamingStrategy().classToTableName( persistentClass.getEntityName() );
256         }
257         else {
258             return mappings.getNamingStrategy().tableName(tableName);
259         }
260     }
261
262     public void bindTable(
263             String JavaDoc schema, String JavaDoc catalog,
264             String JavaDoc tableName, List JavaDoc uniqueConstraints,
265             String JavaDoc constraints, Table denormalizedSuperclassTable
266             ) {
267         Table table = TableBinder.fillTable(
268             schema, catalog,
269             getClassTableName(tableName),
270             persistentClass.isAbstract(), uniqueConstraints, constraints,
271                 denormalizedSuperclassTable, mappings
272         );
273
274         if (persistentClass instanceof TableOwner) {
275             ( (TableOwner) persistentClass).setTable(table);
276         }
277         else {
278             throw new AssertionFailure("binding a table for a subclass");
279         }
280     }
281
282     public void finalSecondaryTableBinding(PropertyHolder propertyHolder) {
283         /*
284          * Those operations has to be done after the id definition of the persistence class.
285          * ie after the properties parsing
286          */

287         Iterator JavaDoc joins = secondaryTables.values().iterator();
288         Iterator JavaDoc joinColumns = secondaryTableJoins.values().iterator();
289
290         while ( joins.hasNext() ) {
291             Object JavaDoc uncastedColumn = joinColumns.next();
292
293             Ejb3JoinColumn[] ejb3JoinColumns;
294             JoinColumn[] columns = null;
295             if ( uncastedColumn instanceof JoinColumn[] ) {
296                 columns = (JoinColumn[]) uncastedColumn;
297             }
298             if (columns == null) {
299                 ejb3JoinColumns = new Ejb3JoinColumn[1];
300                 ejb3JoinColumns[0] = Ejb3JoinColumn.buildJoinColumn(
301                         (JoinColumn) uncastedColumn,
302                         persistentClass.getIdentifier(),
303                         secondaryTables,
304                         propertyHolder, mappings
305                 );
306             }
307             else {
308                 int nbrOfJoinColumns = columns.length;
309                 if (nbrOfJoinColumns == 0) {
310                     ejb3JoinColumns = new Ejb3JoinColumn[1];
311                     ejb3JoinColumns[0] = Ejb3JoinColumn.buildJoinColumn(
312                             (JoinColumn) null,
313                             persistentClass.getIdentifier(),
314                             secondaryTables,
315                             propertyHolder, mappings
316                     );
317                 }
318                 else {
319                     ejb3JoinColumns = new Ejb3JoinColumn[nbrOfJoinColumns];
320                     for (int colIndex = 0 ; colIndex < nbrOfJoinColumns ; colIndex++) {
321                         ejb3JoinColumns[colIndex] = Ejb3JoinColumn.buildJoinColumn(
322                                 columns[colIndex],
323                                 persistentClass.getIdentifier(),
324                                 secondaryTables,
325                                 propertyHolder, mappings
326                         );
327                     }
328                 }
329             }
330
331             for (Ejb3JoinColumn joinColumn : ejb3JoinColumns) {
332                 joinColumn.forceNotNull();
333             }
334             Join join = (Join) joins.next();
335             bindJoinToPersistentClass(join, ejb3JoinColumns, persistentClass, mappings );
336         }
337         mappings.addJoins(persistentClass, secondaryTables);
338     }
339
340     public static void bindJoinToPersistentClass(
341             Join join, Ejb3JoinColumn[] ejb3JoinColumns, PersistentClass persistentClass, ExtendedMappings mappings
342             ) {
343         SimpleValue key = new DependantValue( join.getTable(), persistentClass.getIdentifier() );
344         join.setKey(key);
345         join.setSequentialSelect(false);
346         join.setInverse(false);
347         join.setOptional(true); //perhaps not quite per-spec, but a Good Thing anyway
348
key.setCascadeDeleteEnabled(false);
349         TableBinder.bindFk(persistentClass, null, ejb3JoinColumns, key, false );
350         join.createPrimaryKey();
351         join.createForeignKey();
352         persistentClass.addJoin(join);
353     }
354
355     public void firstLevelSecondaryTablesBinding(SecondaryTable secTable, SecondaryTables secTables, JoinColumn joinCol, JoinColumns joinCols) {
356         if (secTables != null) {
357             //loop through it
358
for (SecondaryTable tab : secTables.value() ) {
359                 bindFirstLevelSecondaryTable(tab, null, null);
360             }
361         }
362         else {
363             if (secTable != null) bindFirstLevelSecondaryTable(secTable, joinCol, joinCols);
364         }
365     }
366
367     private void bindFirstLevelSecondaryTable(SecondaryTable tabAnn, JoinColumn joinColAnn, JoinColumns joinColsAnn) {
368         List JavaDoc uniqueConstraints = new ArrayList JavaDoc();
369         if (tabAnn.uniqueConstraints().length != 0) {
370             for( UniqueConstraint uc : tabAnn.uniqueConstraints() ) {
371                 uniqueConstraints.add( uc.columnNames() );
372             }
373         }
374         addSecondaryTable(
375                 tabAnn.schema(),
376                 tabAnn.catalog(),
377                 tabAnn.name(),
378                 uniqueConstraints,
379                 joinColAnn,
380                 joinColsAnn == null ? tabAnn.join() : joinColsAnn.value()
381         );
382     }
383
384 // /** bind join table for a many to one association table */
385
// private void bindToOneAssociationTable(JoinTable tabAnn) {
386
// List uniqueConstraints = new ArrayList();
387
// String schema;
388
// String catalog;
389
// String tableName;
390
// javax.persistence.Table table = tabAnn.table();
391
// if ( table.specified() ) {
392
// if (table.uniqueConstraints().length != 0) {
393
// for( UniqueConstraint uc : table.uniqueConstraints() ) {
394
// uniqueConstraints.add( uc.columnNames() );
395
// }
396
// }
397
// }
398
// else {
399
// schema = "";
400
// catalog = "";
401
// tableName = "";
402
// }
403
// addSecondaryTable(
404
// tabAnn.schema(),
405
// tabAnn.catalog(),
406
// tabAnn.name(),
407
// uniqueConstraints,
408
// joinColAnn,
409
// joinColsAnn == null ? tabAnn.join() : joinColsAnn.value()
410
// );
411
// }
412

413     public void addSecondaryTable(String JavaDoc schema, String JavaDoc catalog, String JavaDoc table, List JavaDoc uniqueConstraints, JoinColumn joinColAnn, JoinColumn[] joinColArray) {
414         Join join = buildJoin(schema, catalog, table, uniqueConstraints, persistentClass, mappings);
415         //somehow keep joins() for later.
416
//Has to do the work later because it needs persistentClass id!
417
if (joinColAnn != null) {
418             secondaryTableJoins.put( table, joinColAnn );
419         }
420         else {
421             secondaryTableJoins.put( table, joinColArray );
422         }
423         log.info("Mapping class join: " + persistentClass.getEntityName() + " -> " + join.getTable().getName() );
424         secondaryTables.put( table, join );
425     }
426
427     public static Join buildJoin(String JavaDoc schema, String JavaDoc catalog, String JavaDoc table, List JavaDoc uniqueConstraints, PersistentClass persistentClass, ExtendedMappings mappings) {
428         Join join = new Join();
429         join.setPersistentClass(persistentClass);
430         Table tableMapping = TableBinder.fillTable(
431             schema, catalog, table,
432             false, uniqueConstraints, null, null, mappings
433         );
434         //no check constraints available on joins
435
join.setTable(tableMapping);
436         return join;
437     }
438
439     public java.util.Map JavaDoc<String JavaDoc, Join> getSecondaryTables() {
440         return secondaryTables;
441     }
442
443     public void setCache(Cache cacheAnn) {
444         if (cacheAnn != null) {
445             cacheRegion = AnnotationBinder.isDefault( cacheAnn.region() ) ? null : cacheAnn.region();
446             cacheConcurrentStrategy = getCacheConcurrencyStrategy( cacheAnn.usage() );
447         }
448         else {
449             cacheConcurrentStrategy = null;
450             cacheRegion = null;
451         }
452     }
453
454     public static String JavaDoc getCacheConcurrencyStrategy(CacheConcurrencyStrategy strategy) {
455         switch ( strategy ) {
456             case NONE:
457                 return null;
458             case READ_ONLY:
459                 return CacheFactory.READ_ONLY;
460             case READ_WRITE:
461                 return CacheFactory.READ_WRITE;
462             case NONSTRICT_READ_WRITE:
463                 return CacheFactory.NONSTRICT_READ_WRITE;
464             case TRANSACTIONAL:
465                 return CacheFactory.TRANSACTIONAL;
466             default:
467                 throw new AssertionFailure( "CacheConcurrencyStrategy unknown: " + strategy );
468         }
469     }
470
471     public void addFilter(String JavaDoc name, String JavaDoc condition) {
472         filters.put(name, condition);
473     }
474
475     public void setInheritanceState(InheritanceState inheritanceState) {
476         this.inheritanceState = inheritanceState;
477     }
478
479     public InheritanceState getInheritanceState() {
480         return inheritanceState;
481     }
482
483     public boolean isIgnoreIdAnnotations() {
484         return ignoreIdAnnotations;
485     }
486
487     public void setIgnoreIdAnnotations(boolean ignoreIdAnnotations) {
488         this.ignoreIdAnnotations = ignoreIdAnnotations;
489     }
490
491     public void addIndexes(org.hibernate.annotations.Table table) {
492         if (table == null) return;
493         String JavaDoc tableName = table.name();
494         Iterator JavaDoc tables = persistentClass.getTableClosureIterator();
495         Table hibTable = null;
496         while ( tables.hasNext() ) {
497             hibTable = (Table) tables.next();
498             if ( hibTable.getName().equals( tableName) ) {
499                 //we are in the correct table to find columns
500
break;
501             }
502         }
503         if (hibTable == null) {
504             throw new AnnotationException("@org.hibernate.annotations.Table references an unknown table: " + tableName);
505         }
506         TableBinder.addIndexes( hibTable, table.indexes() );
507     }
508
509     public void addIndexes(Tables tables) {
510         if (tables == null) return;
511         for (org.hibernate.annotations.Table table : tables.values() ) {
512             addIndexes( table );
513         }
514     }
515 }
516
Popular Tags