KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > hibernate > persister > entity > UnionSubclassEntityPersister


1 //$Id: UnionSubclassEntityPersister.java,v 1.10 2005/06/14 03:24:35 steveebersole Exp $
2
package org.hibernate.persister.entity;
3
4 import java.io.Serializable JavaDoc;
5 import java.util.HashMap JavaDoc;
6 import java.util.HashSet JavaDoc;
7 import java.util.Iterator JavaDoc;
8 import java.util.Map JavaDoc;
9 import java.util.ArrayList JavaDoc;
10
11 import org.hibernate.AssertionFailure;
12 import org.hibernate.Hibernate;
13 import org.hibernate.HibernateException;
14 import org.hibernate.LockMode;
15 import org.hibernate.MappingException;
16 import org.hibernate.cache.CacheConcurrencyStrategy;
17 import org.hibernate.cfg.Settings;
18 import org.hibernate.dialect.Dialect;
19 import org.hibernate.engine.Mapping;
20 import org.hibernate.engine.SessionFactoryImplementor;
21 import org.hibernate.id.IdentityGenerator;
22 import org.hibernate.mapping.Column;
23 import org.hibernate.mapping.PersistentClass;
24 import org.hibernate.mapping.Subclass;
25 import org.hibernate.mapping.Table;
26 import org.hibernate.sql.SelectFragment;
27 import org.hibernate.sql.SimpleSelect;
28 import org.hibernate.type.Type;
29 import org.hibernate.util.ArrayHelper;
30 import org.hibernate.util.JoinedIterator;
31 import org.hibernate.util.SingletonIterator;
32
33 /**
34  * Implementation of the "table-per-concrete-class" or "roll-down" mapping
35  * strategy for an entity and its inheritence hierarchy.
36  *
37  * @author Gavin King
38  */

39 public class UnionSubclassEntityPersister extends BasicEntityPersister {
40
41     // the class hierarchy structure
42
private final String JavaDoc subquery;
43     private final String JavaDoc tableName;
44     //private final String rootTableName;
45
private final String JavaDoc[] subclassClosure;
46     private final String JavaDoc[] spaces;
47     private final String JavaDoc[] subclassSpaces;
48     private final String JavaDoc discriminatorSQLValue;
49     private final Map JavaDoc subclassByDiscriminatorValue = new HashMap JavaDoc();
50
51     private final String JavaDoc[] constraintOrderedTableNames;
52     private final String JavaDoc[][] constraintOrderedKeyColumnNames;
53
54     //INITIALIZATION:
55

56     public UnionSubclassEntityPersister(
57             final PersistentClass persistentClass,
58             final CacheConcurrencyStrategy cache,
59             final SessionFactoryImplementor factory,
60             final Mapping mapping)
61     throws HibernateException {
62
63         super(persistentClass, cache, factory);
64         
65         if ( getIdentifierGenerator() instanceof IdentityGenerator ) {
66             throw new MappingException(
67                     "Cannot use identity column key generation with <union-subclass> mapping for: " +
68                     getEntityName()
69             );
70         }
71
72         // TABLE
73

74         tableName = persistentClass.getTable().getQualifiedName(
75                 factory.getDialect(),
76                 factory.getSettings().getDefaultCatalogName(),
77                 factory.getSettings().getDefaultSchemaName()
78         );
79         /*rootTableName = persistentClass.getRootTable().getQualifiedName(
80                 factory.getDialect(),
81                 factory.getDefaultCatalog(),
82                 factory.getDefaultSchema()
83         );*/

84
85         //Custom SQL
86
insertCallable = new boolean[] { persistentClass.isCustomInsertCallable() };
87         updateCallable = new boolean[] { persistentClass.isCustomUpdateCallable() };
88         deleteCallable = new boolean[] { persistentClass.isCustomDeleteCallable() };
89         
90         customSQLInsert = new String JavaDoc[] { persistentClass.getCustomSQLInsert() };
91         customSQLUpdate = new String JavaDoc[] { persistentClass.getCustomSQLUpdate() };
92         customSQLDelete = new String JavaDoc[] { persistentClass.getCustomSQLDelete() };
93         
94         discriminatorSQLValue = String.valueOf( persistentClass.getSubclassId() );
95
96         // PROPERTIES
97

98         int subclassSpan = persistentClass.getSubclassSpan() + 1;
99         subclassClosure = new String JavaDoc[subclassSpan];
100         subclassClosure[0] = getEntityName();
101
102         // SUBCLASSES
103
subclassByDiscriminatorValue.put(
104                 new Integer JavaDoc( persistentClass.getSubclassId() ),
105                 persistentClass.getEntityName()
106         );
107         if ( persistentClass.isPolymorphic() ) {
108             Iterator JavaDoc iter = persistentClass.getSubclassIterator();
109             int k=1;
110             while ( iter.hasNext() ) {
111                 Subclass sc = (Subclass) iter.next();
112                 subclassClosure[k++] = sc.getEntityName();
113                 subclassByDiscriminatorValue.put( new Integer JavaDoc( sc.getSubclassId() ), sc.getEntityName() );
114             }
115         }
116         
117         //SPACES
118
//TODO: i'm not sure, but perhaps we should exclude
119
// abstract denormalized tables?
120

121         int spacesSize = 1 + persistentClass.getSynchronizedTables().size();
122         spaces = new String JavaDoc[spacesSize];
123         spaces[0] = tableName;
124         Iterator JavaDoc iter = persistentClass.getSynchronizedTables().iterator();
125         for ( int i=1; i<spacesSize; i++ ) {
126             spaces[i] = (String JavaDoc) iter.next();
127         }
128         
129         HashSet JavaDoc subclassTables = new HashSet JavaDoc();
130         iter = persistentClass.getSubclassTableClosureIterator();
131         while ( iter.hasNext() ) {
132             Table table = (Table) iter.next();
133             subclassTables.add( table.getQualifiedName(
134                     factory.getDialect(),
135                     factory.getSettings().getDefaultCatalogName(),
136                     factory.getSettings().getDefaultSchemaName()
137             ) );
138         }
139         subclassSpaces = ArrayHelper.toStringArray(subclassTables);
140
141         subquery = generateSubquery(persistentClass, mapping);
142
143         if ( isMultiTable() ) {
144             int idColumnSpan = getIdentifierColumnSpan();
145             ArrayList JavaDoc tableNames = new ArrayList JavaDoc();
146             ArrayList JavaDoc keyColumns = new ArrayList JavaDoc();
147             iter = persistentClass.getSubclassTableClosureIterator();
148             while ( iter.hasNext() ) {
149                 Table tab = ( Table ) iter.next();
150                 if ( !tab.isAbstractUnionTable() ) {
151                     String JavaDoc tableName = tab.getQualifiedName(
152                             factory.getDialect(),
153                             factory.getSettings().getDefaultCatalogName(),
154                             factory.getSettings().getDefaultSchemaName()
155                     );
156                     tableNames.add( tableName );
157                     String JavaDoc[] key = new String JavaDoc[idColumnSpan];
158                     Iterator JavaDoc citer = tab.getPrimaryKey().getColumnIterator();
159                     for ( int k=0; k<idColumnSpan; k++ ) {
160                         key[k] = ( ( Column ) citer.next() ).getQuotedName( factory.getDialect() );
161                     }
162                     keyColumns.add( key );
163                 }
164             }
165
166             constraintOrderedTableNames = ArrayHelper.toStringArray( tableNames );
167             constraintOrderedKeyColumnNames = ArrayHelper.to2DStringArray( keyColumns );
168         }
169         else {
170             constraintOrderedTableNames = new String JavaDoc[] { tableName };
171             constraintOrderedKeyColumnNames = new String JavaDoc[][] { getIdentifierColumnNames() };
172         }
173
174         initLockers();
175
176         initSubclassPropertyAliasesMap(persistentClass);
177         
178         postConstruct(mapping);
179
180     }
181
182     public Serializable JavaDoc[] getQuerySpaces() {
183         return subclassSpaces;
184     }
185     
186     public String JavaDoc getTableName() {
187         return subquery;
188     }
189
190     public Type getDiscriminatorType() {
191         return Hibernate.INTEGER;
192     }
193
194     public String JavaDoc getDiscriminatorSQLValue() {
195         return discriminatorSQLValue;
196     }
197
198     public String JavaDoc[] getSubclassClosure() {
199         return subclassClosure;
200     }
201
202     public String JavaDoc getSubclassForDiscriminatorValue(Object JavaDoc value) {
203         return (String JavaDoc) subclassByDiscriminatorValue.get(value);
204     }
205
206     public Serializable JavaDoc[] getPropertySpaces() {
207         return spaces;
208     }
209
210     protected boolean isDiscriminatorFormula() {
211         return false;
212     }
213
214     /**
215      * Generate the SQL that selects a row by id
216      */

217     protected String JavaDoc generateSelectString(LockMode lockMode) {
218         SimpleSelect select = new SimpleSelect( getFactory().getDialect() )
219             .setLockMode(lockMode)
220             .setTableName( getTableName() )
221             .addColumns( getIdentifierColumnNames() )
222             .addColumns(
223                     getSubclassColumnClosure(),
224                     getSubclassColumnAliasClosure(),
225                     getSubclassColumnLazyiness()
226             )
227             .addColumns(
228                     getSubclassFormulaClosure(),
229                     getSubclassFormulaAliasClosure(),
230                     getSubclassFormulaLazyiness()
231             );
232         //TODO: include the rowids!!!!
233
if ( hasSubclasses() ) {
234             if ( isDiscriminatorFormula() ) {
235                 select.addColumn( getDiscriminatorFormula(), getDiscriminatorAlias() );
236             }
237             else {
238                 select.addColumn( getDiscriminatorColumnName(), getDiscriminatorAlias() );
239             }
240         }
241         if ( getFactory().getSettings().isCommentsEnabled() ) {
242             select.setComment( "load " + getEntityName() );
243         }
244         return select.addCondition( getIdentifierColumnNames(), "=?" ).toStatementString();
245     }
246
247     protected String JavaDoc getDiscriminatorFormula() {
248         return null;
249     }
250
251     protected String JavaDoc getTableName(int j) {
252         return tableName;
253     }
254
255     protected String JavaDoc[] getKeyColumns(int j) {
256         return getIdentifierColumnNames();
257     }
258     
259     protected boolean isTableCascadeDeleteEnabled(int j) {
260         return false;
261     }
262     
263     protected boolean isPropertyOfTable(int property, int j) {
264         return true;
265     }
266
267     // Execute the SQL:
268

269     public String JavaDoc fromTableFragment(String JavaDoc name) {
270         return getTableName() + ' ' + name;
271     }
272
273     public String JavaDoc filterFragment(String JavaDoc name) {
274         return hasWhere() ?
275             " and " + getSQLWhereString(name) :
276             "";
277     }
278
279     public String JavaDoc getSubclassPropertyTableName(int i) {
280         return getTableName();//ie. the subquery! yuck!
281
}
282
283     protected void addDiscriminatorToSelect(SelectFragment select, String JavaDoc name, String JavaDoc suffix) {
284         select.addColumn( name, getDiscriminatorColumnName(), getDiscriminatorAlias() );
285     }
286     
287     protected int[] getPropertyTableNumbersInSelect() {
288         return new int[ getPropertySpan() ];
289     }
290
291     protected int getSubclassPropertyTableNumber(int i) {
292         return 0;
293     }
294
295     public int getSubclassPropertyTableNumber(String JavaDoc propertyName) {
296         return 0;
297     }
298
299     public boolean isMultiTable() {
300         // This could also just be true all the time...
301
return isAbstract() || hasSubclasses();
302     }
303
304     public int getTableSpan() {
305         return 1;
306     }
307
308     protected int[] getSubclassColumnTableNumberClosure() {
309         return new int[ getSubclassColumnClosure().length ];
310     }
311
312     protected int[] getSubclassFormulaTableNumberClosure() {
313         return new int[ getSubclassFormulaClosure().length ];
314     }
315
316     protected boolean[] getTableHasColumns() {
317         return new boolean[] { true };
318     }
319
320     protected int[] getPropertyTableNumbers() {
321         return new int[ getPropertySpan() ];
322     }
323
324     protected String JavaDoc generateSubquery(PersistentClass model, Mapping mapping) {
325
326         Dialect dialect = getFactory().getDialect();
327         Settings settings = getFactory().getSettings();
328         
329         if ( !model.hasSubclasses() ) {
330             return model.getTable().getQualifiedName(
331                     dialect,
332                     settings.getDefaultCatalogName(),
333                     settings.getDefaultSchemaName()
334                 );
335         }
336
337         HashSet JavaDoc columns = new HashSet JavaDoc();
338         Iterator JavaDoc titer = model.getSubclassTableClosureIterator();
339         while ( titer.hasNext() ) {
340             Table table = (Table) titer.next();
341             if ( !table.isAbstractUnionTable() ) {
342                 Iterator JavaDoc citer = table.getColumnIterator();
343                 while ( citer.hasNext() ) columns.add( citer.next() );
344             }
345         }
346
347         StringBuffer JavaDoc buf = new StringBuffer JavaDoc()
348             .append("( ");
349
350         Iterator JavaDoc siter = new JoinedIterator(
351             new SingletonIterator(model),
352             model.getSubclassIterator()
353         );
354
355         while ( siter.hasNext() ) {
356             PersistentClass clazz = (PersistentClass) siter.next();
357             Table table = clazz.getTable();
358             if ( !table.isAbstractUnionTable() ) {
359                 //TODO: move to .sql package!!
360
buf.append("select ");
361                 Iterator JavaDoc citer = columns.iterator();
362                 while ( citer.hasNext() ) {
363                     Column col = (Column) citer.next();
364                     if ( !table.containsColumn(col) ) {
365                         int sqlType = col.getSqlTypeCode(mapping);
366                         buf.append( dialect.getSelectClauseNullString(sqlType) )
367                             .append(" as ");
368                     }
369                     buf.append( col.getName() );
370                     buf.append(", ");
371                 }
372                 buf.append( clazz.getSubclassId() )
373                     .append(" as clazz_");
374                 buf.append(" from ")
375                     .append( table.getQualifiedName(
376                             dialect,
377                             settings.getDefaultCatalogName(),
378                             settings.getDefaultSchemaName()
379                     ) );
380                 buf.append(" union ");
381                 if ( dialect.supportsUnionAll() ) {
382                     buf.append("all ");
383                 }
384             }
385         }
386         
387         if ( buf.length() > 2 ) {
388             //chop the last union (all)
389
buf.setLength( buf.length() - ( dialect.supportsUnionAll() ? 11 : 7 ) );
390         }
391
392         return buf.append(" )").toString();
393     }
394
395     protected String JavaDoc[] getSubclassTableKeyColumns(int j) {
396         if (j!=0) throw new AssertionFailure("only one table");
397         return getIdentifierColumnNames();
398     }
399
400     public String JavaDoc getSubclassTableName(int j) {
401         if (j!=0) throw new AssertionFailure("only one table");
402         return tableName;
403     }
404
405     public int getSubclassTableSpan() {
406         return 1;
407     }
408
409     protected boolean isClassOrSuperclassTable(int j) {
410         if (j!=0) throw new AssertionFailure("only one table");
411         return true;
412     }
413
414     public String JavaDoc getPropertyTableName(String JavaDoc propertyName) {
415         //TODO: check this....
416
return getTableName();
417     }
418
419     public String JavaDoc[] getConstraintOrderedTableNameClosure() {
420             return constraintOrderedTableNames;
421     }
422
423     public String JavaDoc[][] getContraintOrderedTableKeyColumnClosure() {
424         return constraintOrderedKeyColumnNames;
425     }
426 }
427
Popular Tags