KickJava   Java API By Example, From Geeks To Geeks.

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


1 // $Id: HbmBinder.java,v 1.116 2005/07/21 01:58:44 oneovthafew Exp $
2
package org.hibernate.cfg;
3
4 import java.io.Serializable JavaDoc;
5 import java.util.ArrayList JavaDoc;
6 import java.util.Comparator JavaDoc;
7 import java.util.HashMap JavaDoc;
8 import java.util.HashSet JavaDoc;
9 import java.util.Iterator JavaDoc;
10 import java.util.Properties JavaDoc;
11 import java.util.StringTokenizer JavaDoc;
12
13 import org.apache.commons.collections.SequencedHashMap;
14 import org.apache.commons.logging.Log;
15 import org.apache.commons.logging.LogFactory;
16 import org.dom4j.Attribute;
17 import org.dom4j.Document;
18 import org.dom4j.Element;
19 import org.hibernate.EntityMode;
20 import org.hibernate.FetchMode;
21 import org.hibernate.FlushMode;
22 import org.hibernate.LockMode;
23 import org.hibernate.MappingException;
24 import org.hibernate.engine.FilterDefinition;
25 import org.hibernate.engine.NamedQueryDefinition;
26 import org.hibernate.engine.NamedSQLQueryDefinition;
27 import org.hibernate.engine.ResultSetMappingDefinition;
28 import org.hibernate.engine.Versioning;
29 import org.hibernate.id.PersistentIdentifierGenerator;
30 import org.hibernate.loader.custom.SQLQueryCollectionReturn;
31 import org.hibernate.loader.custom.SQLQueryJoinReturn;
32 import org.hibernate.loader.custom.SQLQueryRootReturn;
33 import org.hibernate.loader.custom.SQLQueryScalarReturn;
34 import org.hibernate.mapping.Any;
35 import org.hibernate.mapping.Array;
36 import org.hibernate.mapping.Backref;
37 import org.hibernate.mapping.Bag;
38 import org.hibernate.mapping.Collection;
39 import org.hibernate.mapping.Column;
40 import org.hibernate.mapping.Component;
41 import org.hibernate.mapping.DependantValue;
42 import org.hibernate.mapping.Fetchable;
43 import org.hibernate.mapping.Filterable;
44 import org.hibernate.mapping.Formula;
45 import org.hibernate.mapping.IdentifierBag;
46 import org.hibernate.mapping.IdentifierCollection;
47 import org.hibernate.mapping.IndexBackref;
48 import org.hibernate.mapping.IndexedCollection;
49 import org.hibernate.mapping.Join;
50 import org.hibernate.mapping.JoinedSubclass;
51 import org.hibernate.mapping.KeyValue;
52 import org.hibernate.mapping.List;
53 import org.hibernate.mapping.ManyToOne;
54 import org.hibernate.mapping.Map;
55 import org.hibernate.mapping.MetaAttribute;
56 import org.hibernate.mapping.OneToMany;
57 import org.hibernate.mapping.OneToOne;
58 import org.hibernate.mapping.PersistentClass;
59 import org.hibernate.mapping.PrimitiveArray;
60 import org.hibernate.mapping.Property;
61 import org.hibernate.mapping.RootClass;
62 import org.hibernate.mapping.Selectable;
63 import org.hibernate.mapping.Set;
64 import org.hibernate.mapping.SimpleValue;
65 import org.hibernate.mapping.SingleTableSubclass;
66 import org.hibernate.mapping.Subclass;
67 import org.hibernate.mapping.Table;
68 import org.hibernate.mapping.ToOne;
69 import org.hibernate.mapping.TypeDef;
70 import org.hibernate.mapping.UnionSubclass;
71 import org.hibernate.mapping.UniqueKey;
72 import org.hibernate.mapping.Value;
73 import org.hibernate.persister.entity.JoinedSubclassEntityPersister;
74 import org.hibernate.persister.entity.SingleTableEntityPersister;
75 import org.hibernate.persister.entity.UnionSubclassEntityPersister;
76 import org.hibernate.type.DiscriminatorType;
77 import org.hibernate.type.ForeignKeyDirection;
78 import org.hibernate.type.Type;
79 import org.hibernate.type.TypeFactory;
80 import org.hibernate.util.ArrayHelper;
81 import org.hibernate.util.CollectionHelper;
82 import org.hibernate.util.JoinedIterator;
83 import org.hibernate.util.ReflectHelper;
84 import org.hibernate.util.StringHelper;
85
86 /**
87  * Walks an XML mapping document and produces the Hibernate configuration-time metamodel (the
88  * classes in the <tt>mapping</tt> package)
89  *
90  * @author Gavin King
91  */

92 public final class HbmBinder {
93
94     private static final Log log = LogFactory.getLog( HbmBinder.class );
95
96     /**
97      * Private constructor to disallow instantiation.
98      */

99     private HbmBinder() {
100     }
101
102     /**
103      * The main contract into the hbm.xml-based binder. Performs necessary binding operations
104      * represented by the given DOM.
105      *
106      * @param doc The DOM to be parsed and bound.
107      * @param mappings Current bind state.
108      * @param inheritedMetas Any inherited meta-tag information.
109      * @throws MappingException
110      */

111     public static void bindRoot(Document doc, Mappings mappings, java.util.Map JavaDoc inheritedMetas)
112             throws MappingException {
113
114         java.util.List JavaDoc names = HbmBinder.getExtendsNeeded( doc, mappings );
115         if ( !names.isEmpty() ) {
116             // classes mentioned in extends not available - so put it in queue
117
for ( Iterator JavaDoc iter = names.iterator(); iter.hasNext(); ) {
118                 String JavaDoc className = (String JavaDoc) iter.next();
119                 mappings.addToExtendsQueue( className, doc );
120             }
121             return;
122         }
123
124         Element hmNode = doc.getRootElement();
125         inheritedMetas = getMetas( hmNode, inheritedMetas, true ); // get meta's from
126
// <hibernate-mapping>
127
extractRootAttributes( hmNode, mappings );
128
129         Iterator JavaDoc filterDefs = hmNode.elementIterator( "filter-def" );
130         while ( filterDefs.hasNext() ) {
131             parseFilterDef( (Element) filterDefs.next(), mappings );
132         }
133
134         Iterator JavaDoc typeDefs = hmNode.elementIterator( "typedef" );
135         while ( typeDefs.hasNext() ) {
136             Element typeDef = (Element) typeDefs.next();
137             String JavaDoc typeClass = typeDef.attributeValue( "class" );
138             String JavaDoc typeName = typeDef.attributeValue( "name" );
139             Iterator JavaDoc paramIter = typeDef.elementIterator( "param" );
140             Properties JavaDoc parameters = new Properties JavaDoc();
141             while ( paramIter.hasNext() ) {
142                 Element param = (Element) paramIter.next();
143                 parameters.setProperty( param.attributeValue( "name" ), param.getTextTrim() );
144             }
145
146             mappings.addTypeDef( typeName, typeClass, parameters );
147         }
148
149         Iterator JavaDoc nodes = hmNode.elementIterator( "class" );
150         while ( nodes.hasNext() ) {
151             Element n = (Element) nodes.next();
152             RootClass rootclass = new RootClass();
153             bindRootClass( n, rootclass, mappings, inheritedMetas );
154             mappings.addClass( rootclass );
155         }
156
157         Iterator JavaDoc subclassnodes = hmNode.elementIterator( "subclass" );
158         while ( subclassnodes.hasNext() ) {
159             Element subnode = (Element) subclassnodes.next();
160             PersistentClass superModel = getSuperclass( mappings, subnode );
161             handleSubclass( superModel, mappings, subnode, inheritedMetas );
162         }
163
164         Iterator JavaDoc joinedsubclassnodes = hmNode.elementIterator( "joined-subclass" );
165         while ( joinedsubclassnodes.hasNext() ) {
166             Element subnode = (Element) joinedsubclassnodes.next();
167             PersistentClass superModel = getSuperclass( mappings, subnode );
168             handleJoinedSubclass( superModel, mappings, subnode, inheritedMetas );
169         }
170
171         Iterator JavaDoc unionsubclassnodes = hmNode.elementIterator( "union-subclass" );
172         while ( unionsubclassnodes.hasNext() ) {
173             Element subnode = (Element) unionsubclassnodes.next();
174             PersistentClass superModel = getSuperclass( mappings, subnode );
175             handleUnionSubclass( superModel, mappings, subnode, inheritedMetas );
176         }
177
178         nodes = hmNode.elementIterator( "query" );
179         while ( nodes.hasNext() ) {
180             bindNamedQuery( (Element) nodes.next(), null, mappings );
181         }
182
183         nodes = hmNode.elementIterator( "sql-query" );
184         while ( nodes.hasNext() ) {
185             bindNamedSQLQuery( (Element) nodes.next(), null, mappings );
186         }
187
188         nodes = hmNode.elementIterator( "resultset" );
189         while ( nodes.hasNext() ) {
190             bindResultSetMappingDefinition( (Element) nodes.next(), null, mappings );
191         }
192
193         nodes = hmNode.elementIterator( "import" );
194         while ( nodes.hasNext() ) {
195             Element n = (Element) nodes.next();
196             String JavaDoc className = getClassName( n.attribute( "class" ), mappings );
197             Attribute renameNode = n.attribute( "rename" );
198             String JavaDoc rename = ( renameNode == null )
199                 ? StringHelper.unqualify( className )
200                 : renameNode.getValue();
201             log.debug( "Import: " + rename + " -> " + className );
202             mappings.addImport( className, rename );
203         }
204     }
205
206     private static void extractRootAttributes(Element hmNode, Mappings mappings) {
207         Attribute schemaNode = hmNode.attribute( "schema" );
208         mappings.setSchemaName( ( schemaNode == null ) ? null : schemaNode.getValue() );
209
210         Attribute catalogNode = hmNode.attribute( "catalog" );
211         mappings.setCatalogName( ( catalogNode == null ) ? null : catalogNode.getValue() );
212
213         Attribute dcNode = hmNode.attribute( "default-cascade" );
214         mappings.setDefaultCascade( ( dcNode == null ) ? "none" : dcNode.getValue() );
215
216         Attribute daNode = hmNode.attribute( "default-access" );
217         mappings.setDefaultAccess( ( daNode == null ) ? "property" : daNode.getValue() );
218
219         Attribute dlNode = hmNode.attribute( "default-lazy" );
220         mappings.setDefaultLazy( dlNode == null || dlNode.getValue().equals( "true" ) );
221
222         Attribute aiNode = hmNode.attribute( "auto-import" );
223         mappings.setAutoImport( ( aiNode == null ) ? true : "true".equals( aiNode.getValue() ) );
224
225         Attribute packNode = hmNode.attribute( "package" );
226         if ( packNode != null ) mappings.setDefaultPackage( packNode.getValue() );
227     }
228
229     /**
230      * Responsible for perfoming the bind operation related to an &lt;class/&gt; mapping element.
231      *
232      * @param node The DOM Element for the &lt;class/&gt; element.
233      * @param rootClass The mapping instance to which to bind the information.
234      * @param mappings The current bind state.
235      * @param inheritedMetas Any inherited meta-tag information.
236      * @throws MappingException
237      */

238     public static void bindRootClass(Element node, RootClass rootClass, Mappings mappings,
239             java.util.Map JavaDoc inheritedMetas) throws MappingException {
240         bindClass( node, rootClass, mappings, inheritedMetas );
241         inheritedMetas = getMetas( node, inheritedMetas, true ); // get meta's from <class>
242
bindRootPersistentClassCommonValues( node, inheritedMetas, mappings, rootClass );
243     }
244
245     private static void bindRootPersistentClassCommonValues(Element node,
246             java.util.Map JavaDoc inheritedMetas, Mappings mappings, RootClass entity)
247             throws MappingException {
248
249         // DB-OBJECTNAME
250

251         Attribute schemaNode = node.attribute( "schema" );
252         String JavaDoc schema = schemaNode == null ? mappings.getSchemaName() : schemaNode.getValue();
253
254         Attribute catalogNode = node.attribute( "catalog" );
255         String JavaDoc catalog = catalogNode == null ? mappings.getCatalogName() : catalogNode.getValue();
256
257         Table table = mappings.addTable(
258                 schema,
259                 catalog,
260                 getClassTableName( entity, node, mappings ),
261                 getSubselect( node ),
262                 entity.isAbstract()
263             );
264         entity.setTable( table );
265         bindComment(table, node);
266         
267         log.info( "Mapping class: "
268                 + entity.getEntityName()
269                 + " -> "
270                 + entity.getTable().getName() );
271
272         // MUTABLE
273
Attribute mutableNode = node.attribute( "mutable" );
274         entity.setMutable( ( mutableNode == null ) || mutableNode.getValue().equals( "true" ) );
275
276         // WHERE
277
Attribute whereNode = node.attribute( "where" );
278         if ( whereNode != null ) entity.setWhere( whereNode.getValue() );
279
280         // CHECK
281
Attribute chNode = node.attribute( "check" );
282         if ( chNode != null ) table.addCheckConstraint( chNode.getValue() );
283
284         // POLYMORPHISM
285
Attribute polyNode = node.attribute( "polymorphism" );
286         entity.setExplicitPolymorphism( ( polyNode != null )
287             && polyNode.getValue().equals( "explicit" ) );
288
289         // ROW ID
290
Attribute rowidNode = node.attribute( "rowid" );
291         if ( rowidNode != null ) table.setRowId( rowidNode.getValue() );
292
293         Iterator JavaDoc subnodes = node.elementIterator();
294         while ( subnodes.hasNext() ) {
295
296             Element subnode = (Element) subnodes.next();
297             String JavaDoc name = subnode.getName();
298
299             if ( "id".equals( name ) ) {
300                 // ID
301
bindSimpleId( subnode, entity, mappings, inheritedMetas );
302             }
303             else if ( "composite-id".equals( name ) ) {
304                 // COMPOSITE-ID
305
bindCompositeId( subnode, entity, mappings, inheritedMetas );
306             }
307             else if ( "version".equals( name ) || "timestamp".equals( name ) ) {
308                 // VERSION / TIMESTAMP
309
bindVersioningProperty( table, subnode, mappings, name, entity, inheritedMetas );
310             }
311             else if ( "discriminator".equals( name ) ) {
312                 // DISCRIMINATOR
313
bindDiscriminatorProperty( table, entity, subnode, mappings );
314             }
315             else if ( "cache".equals( name ) ) {
316                 entity.setCacheConcurrencyStrategy( subnode.attributeValue( "usage" ) );
317                 entity.setCacheRegionName( subnode.attributeValue( "region" ) );
318             }
319
320         }
321
322         // Primary key constraint
323
entity.createPrimaryKey();
324
325         createClassProperties( node, entity, mappings, inheritedMetas );
326     }
327
328     private static void bindSimpleId(Element idNode, RootClass entity, Mappings mappings,
329             java.util.Map JavaDoc inheritedMetas) throws MappingException {
330         String JavaDoc propertyName = idNode.attributeValue( "name" );
331
332         SimpleValue id = new SimpleValue( entity.getTable() );
333         entity.setIdentifier( id );
334
335         // if ( propertyName == null || entity.getPojoRepresentation() == null ) {
336
// bindSimpleValue( idNode, id, false, RootClass.DEFAULT_IDENTIFIER_COLUMN_NAME, mappings );
337
// if ( !id.isTypeSpecified() ) {
338
// throw new MappingException( "must specify an identifier type: " + entity.getEntityName()
339
// );
340
// }
341
// }
342
// else {
343
// bindSimpleValue( idNode, id, false, propertyName, mappings );
344
// PojoRepresentation pojo = entity.getPojoRepresentation();
345
// id.setTypeUsingReflection( pojo.getClassName(), propertyName );
346
//
347
// Property prop = new Property();
348
// prop.setValue( id );
349
// bindProperty( idNode, prop, mappings, inheritedMetas );
350
// entity.setIdentifierProperty( prop );
351
// }
352

353         if ( propertyName == null ) {
354             bindSimpleValue( idNode, id, false, RootClass.DEFAULT_IDENTIFIER_COLUMN_NAME, mappings );
355         }
356         else {
357             bindSimpleValue( idNode, id, false, propertyName, mappings );
358         }
359
360         if ( propertyName == null || !entity.hasPojoRepresentation() ) {
361             if ( !id.isTypeSpecified() ) {
362                 throw new MappingException( "must specify an identifier type: "
363                     + entity.getEntityName() );
364             }
365         }
366         else {
367             id.setTypeUsingReflection( entity.getClassName(), propertyName );
368         }
369
370         if ( propertyName != null ) {
371             Property prop = new Property();
372             prop.setValue( id );
373             bindProperty( idNode, prop, mappings, inheritedMetas );
374             entity.setIdentifierProperty( prop );
375         }
376
377         // TODO:
378
/*
379          * if ( id.getHibernateType().getReturnedClass().isArray() ) throw new MappingException(
380          * "illegal use of an array as an identifier (arrays don't reimplement equals)" );
381          */

382         makeIdentifier( idNode, id, mappings );
383     }
384
385     private static void bindCompositeId(Element idNode, RootClass entity, Mappings mappings,
386             java.util.Map JavaDoc inheritedMetas) throws MappingException {
387         String JavaDoc propertyName = idNode.attributeValue( "name" );
388         Component id = new Component( entity );
389         entity.setIdentifier( id );
390         bindCompositeId( idNode, id, entity, propertyName, mappings, inheritedMetas );
391         if ( propertyName == null ) {
392             entity.setEmbeddedIdentifier( id.isEmbedded() );
393             if ( id.isEmbedded() ) {
394                 // todo : what is the implication of this?
395
id.setDynamic( !entity.hasPojoRepresentation() );
396                 /*
397                  * Property prop = new Property(); prop.setName("id");
398                  * prop.setPropertyAccessorName("embedded"); prop.setValue(id);
399                  * entity.setIdentifierProperty(prop);
400                  */

401             }
402         }
403         else {
404             Property prop = new Property();
405             prop.setValue( id );
406             bindProperty( idNode, prop, mappings, inheritedMetas );
407             entity.setIdentifierProperty( prop );
408         }
409
410         makeIdentifier( idNode, id, mappings );
411
412     }
413
414     private static void bindVersioningProperty(Table table, Element subnode, Mappings mappings,
415             String JavaDoc name, RootClass entity, java.util.Map JavaDoc inheritedMetas) {
416
417         String JavaDoc propertyName = subnode.attributeValue( "name" );
418         SimpleValue val = new SimpleValue( table );
419         bindSimpleValue( subnode, val, false, propertyName, mappings );
420         if ( !val.isTypeSpecified() ) {
421             val.setTypeName( "version".equals( name ) ? "integer" : "timestamp" );
422         }
423         Property prop = new Property();
424         prop.setValue( val );
425         bindProperty( subnode, prop, mappings, inheritedMetas );
426         makeVersion( subnode, val );
427         entity.setVersion( prop );
428         entity.addProperty( prop );
429     }
430
431     private static void bindDiscriminatorProperty(Table table, RootClass entity, Element subnode,
432             Mappings mappings) {
433         SimpleValue discrim = new SimpleValue( table );
434         entity.setDiscriminator( discrim );
435         bindSimpleValue(
436                 subnode,
437                 discrim,
438                 false,
439                 RootClass.DEFAULT_DISCRIMINATOR_COLUMN_NAME,
440                 mappings
441             );
442         if ( !discrim.isTypeSpecified() ) {
443             discrim.setTypeName( "string" );
444             // ( (Column) discrim.getColumnIterator().next() ).setType(type);
445
}
446         entity.setPolymorphic( true );
447         if ( "true".equals( subnode.attributeValue( "force" ) ) )
448             entity.setForceDiscriminator( true );
449         if ( "false".equals( subnode.attributeValue( "insert" ) ) )
450             entity.setDiscriminatorInsertable( false );
451     }
452
453     public static void bindClass(Element node, PersistentClass persistentClass, Mappings mappings,
454             java.util.Map JavaDoc inheritedMetas) throws MappingException {
455         // transfer an explicitly defined entity name
456
// handle the lazy attribute
457
Attribute lazyNode = node.attribute( "lazy" );
458         boolean lazy = lazyNode == null ? mappings.isDefaultLazy() : "true".equals( lazyNode
459             .getValue() );
460         // go ahead and set the lazy here, since pojo.proxy can override it.
461
persistentClass.setLazy( lazy );
462
463         String JavaDoc entityName = node.attributeValue( "entity-name" );
464         if ( entityName == null ) entityName = getClassName( node.attribute("name"), mappings );
465         if ( entityName==null ) {
466             throw new MappingException( "Unable to determine entity name" );
467         }
468         persistentClass.setEntityName( entityName );
469
470         bindPojoRepresentation( node, persistentClass, mappings, inheritedMetas );
471         bindDom4jRepresentation( node, persistentClass, mappings, inheritedMetas );
472         bindMapRepresentation( node, persistentClass, mappings, inheritedMetas );
473
474         bindPersistentClassCommonValues( node, persistentClass, mappings, inheritedMetas );
475
476     }
477
478     private static void bindPojoRepresentation(Element node, PersistentClass entity,
479             Mappings mappings, java.util.Map JavaDoc metaTags) {
480
481         String JavaDoc className = getClassName( node.attribute( "name" ), mappings );
482         String JavaDoc proxyName = getClassName( node.attribute( "proxy" ), mappings );
483
484         entity.setClassName( className );
485
486         if ( proxyName != null ) {
487             entity.setProxyInterfaceName( proxyName );
488             entity.setLazy( true );
489         }
490         else if ( entity.isLazy() ) {
491             entity.setProxyInterfaceName( className );
492         }
493
494         Element tuplizer = locateTuplizerDefinition( node, EntityMode.POJO );
495         if ( tuplizer != null ) {
496             entity.addTuplizer( EntityMode.POJO, tuplizer.attributeValue( "class" ) );
497         }
498     }
499
500     private static void bindDom4jRepresentation(Element node, PersistentClass entity,
501             Mappings mappings, java.util.Map JavaDoc inheritedMetas) {
502         String JavaDoc nodeName = node.attributeValue( "node" );
503         if (nodeName==null) nodeName = StringHelper.unqualify( entity.getEntityName() );
504         entity.setNodeName(nodeName);
505
506         Element tuplizer = locateTuplizerDefinition( node, EntityMode.DOM4J );
507         if ( tuplizer != null ) {
508             entity.addTuplizer( EntityMode.DOM4J, tuplizer.attributeValue( "class" ) );
509         }
510     }
511
512     private static void bindMapRepresentation(Element node, PersistentClass entity,
513             Mappings mappings, java.util.Map JavaDoc inheritedMetas) {
514         Element tuplizer = locateTuplizerDefinition( node, EntityMode.MAP );
515         if ( tuplizer != null ) {
516             entity.addTuplizer( EntityMode.MAP, tuplizer.attributeValue( "class" ) );
517         }
518     }
519
520     /**
521      * Locate any explicit tuplizer definition in the metadata, for the given entity-mode.
522      *
523      * @param container The containing element (representing the entity/component)
524      * @param entityMode The entity-mode for which to locate the tuplizer element
525      * @return The tuplizer element, or null.
526      */

527     private static Element locateTuplizerDefinition(Element container, EntityMode entityMode) {
528         Iterator JavaDoc itr = container.elements( "tuplizer" ).iterator();
529         while( itr.hasNext() ) {
530             final Element tuplizerElem = ( Element ) itr.next();
531             if ( entityMode.toString().equals( tuplizerElem.attributeValue( "entity-mode") ) ) {
532                 return tuplizerElem;
533             }
534         }
535         return null;
536     }
537
538     private static void bindPersistentClassCommonValues(Element node, PersistentClass entity,
539             Mappings mappings, java.util.Map JavaDoc inheritedMetas) throws MappingException {
540         // DISCRIMINATOR
541
Attribute discriminatorNode = node.attribute( "discriminator-value" );
542         entity.setDiscriminatorValue( ( discriminatorNode == null )
543             ? entity.getEntityName()
544             : discriminatorNode.getValue() );
545
546         // DYNAMIC UPDATE
547
Attribute dynamicNode = node.attribute( "dynamic-update" );
548         entity.setDynamicUpdate( ( dynamicNode == null ) ? false : "true".equals( dynamicNode
549             .getValue() ) );
550
551         // DYNAMIC INSERT
552
Attribute insertNode = node.attribute( "dynamic-insert" );
553         entity.setDynamicInsert( ( insertNode == null ) ? false : "true".equals( insertNode
554             .getValue() ) );
555
556         // IMPORT
557
mappings.addImport( entity.getEntityName(), entity.getEntityName() );
558         if ( mappings.isAutoImport() && entity.getEntityName().indexOf( '.' ) > 0 ) {
559             mappings.addImport( entity.getEntityName(), StringHelper.unqualify( entity
560                 .getEntityName() ) );
561         }
562
563         // BATCH SIZE
564
Attribute batchNode = node.attribute( "batch-size" );
565         if ( batchNode != null ) entity.setBatchSize( Integer.parseInt( batchNode.getValue() ) );
566
567         // SELECT BEFORE UPDATE
568
Attribute sbuNode = node.attribute( "select-before-update" );
569         if ( sbuNode != null ) entity.setSelectBeforeUpdate( "true".equals( sbuNode.getValue() ) );
570
571         // OPTIMISTIC LOCK MODE
572
Attribute olNode = node.attribute( "optimistic-lock" );
573         entity.setOptimisticLockMode( getOptimisticLockMode( olNode ) );
574
575         entity.setMetaAttributes( getMetas( node, inheritedMetas ) );
576
577         // PERSISTER
578
Attribute persisterNode = node.attribute( "persister" );
579         if ( persisterNode == null ) {
580             // persister = SingleTableEntityPersister.class;
581
}
582         else {
583             try {
584                 entity.setEntityPersisterClass( ReflectHelper.classForName( persisterNode
585                     .getValue() ) );
586             }
587             catch (ClassNotFoundException JavaDoc cnfe) {
588                 throw new MappingException( "Could not find persister class: "
589                     + persisterNode.getValue() );
590             }
591         }
592
593         // CUSTOM SQL
594
handleCustomSQL( node, entity );
595
596         Iterator JavaDoc tables = node.elementIterator( "synchronize" );
597         while ( tables.hasNext() ) {
598             entity.addSynchronizedTable( ( (Element) tables.next() ).attributeValue( "table" ) );
599         }
600
601         Attribute abstractNode = node.attribute( "abstract" );
602         if ( abstractNode != null ) entity.setAbstract( "true".equals( abstractNode.getValue() ) );
603     }
604
605     private static void handleCustomSQL(Element node, PersistentClass model)
606             throws MappingException {
607         Element element = node.element( "sql-insert" );
608         if ( element != null ) {
609             boolean callable = false;
610             callable = isCallable( element );
611             model.setCustomSQLInsert( element.getText(), callable );
612         }
613
614         element = node.element( "sql-delete" );
615         if ( element != null ) {
616             boolean callable = false;
617             callable = isCallable( element );
618             model.setCustomSQLDelete( element.getText(), callable );
619         }
620
621         element = node.element( "sql-update" );
622         if ( element != null ) {
623             boolean callable = false;
624             callable = isCallable( element );
625             model.setCustomSQLUpdate( element.getText(), callable );
626         }
627
628         element = node.element( "loader" );
629         if ( element != null ) {
630             model.setLoaderName( element.attributeValue( "query-ref" ) );
631         }
632     }
633
634     private static void handleCustomSQL(Element node, Join model) throws MappingException {
635         Element element = node.element( "sql-insert" );
636         if ( element != null ) {
637             boolean callable = false;
638             callable = isCallable( element );
639             model.setCustomSQLInsert( element.getText(), callable );
640         }
641
642         element = node.element( "sql-delete" );
643         if ( element != null ) {
644             boolean callable = false;
645             callable = isCallable( element );
646             model.setCustomSQLDelete( element.getText(), callable );
647         }
648
649         element = node.element( "sql-update" );
650         if ( element != null ) {
651             boolean callable = false;
652             callable = isCallable( element );
653             model.setCustomSQLUpdate( element.getText(), callable );
654         }
655     }
656
657     private static void handleCustomSQL(Element node, Collection model) throws MappingException {
658         Element element = node.element( "sql-insert" );
659         if ( element != null ) {
660             boolean callable = false;
661             callable = isCallable( element, true );
662             model.setCustomSQLInsert( element.getText(), callable );
663         }
664
665         element = node.element( "sql-delete" );
666         if ( element != null ) {
667             boolean callable = false;
668             callable = isCallable( element, true );
669             model.setCustomSQLDelete( element.getText(), callable );
670         }
671
672         element = node.element( "sql-update" );
673         if ( element != null ) {
674             boolean callable = false;
675             callable = isCallable( element, true );
676             model.setCustomSQLUpdate( element.getText(), callable );
677         }
678
679         element = node.element( "sql-delete-all" );
680         if ( element != null ) {
681             boolean callable = false;
682             callable = isCallable( element, true );
683             model.setCustomSQLDeleteAll( element.getText(), callable );
684         }
685     }
686
687     private static boolean isCallable(Element e) throws MappingException {
688         return isCallable( e, true );
689     }
690
691     /**
692      * @param element
693      * @param supportsCallable
694      * @return
695      */

696     private static boolean isCallable(Element element, boolean supportsCallable)
697             throws MappingException {
698         Attribute attrib = element.attribute( "callable" );
699         if ( attrib != null && "true".equals( attrib.getValue() ) ) {
700             if ( !supportsCallable ) {
701                 throw new MappingException( "callable attribute not supported yet!" );
702             }
703             return true;
704         }
705         return false;
706     }
707
708     public static void bindUnionSubclass(Element node, UnionSubclass unionSubclass,
709             Mappings mappings, java.util.Map JavaDoc inheritedMetas) throws MappingException {
710
711         bindClass( node, unionSubclass, mappings, inheritedMetas );
712         inheritedMetas = getMetas( node, inheritedMetas, true ); // get meta's from <subclass>
713

714         if ( unionSubclass.getEntityPersisterClass() == null ) {
715             unionSubclass.getRootClass().setEntityPersisterClass(
716                 UnionSubclassEntityPersister.class );
717         }
718
719         Attribute schemaNode = node.attribute( "schema" );
720         String JavaDoc schema = schemaNode == null ? mappings.getSchemaName() : schemaNode.getValue();
721
722         Attribute catalogNode = node.attribute( "catalog" );
723         String JavaDoc catalog = catalogNode == null ? mappings.getCatalogName() : catalogNode.getValue();
724
725         Table mytable = mappings.addDenormalizedTable(
726                 schema,
727                 catalog,
728                 getClassTableName(unionSubclass, node, mappings ),
729                 unionSubclass.isAbstract(),
730                 getSubselect( node ),
731                 unionSubclass.getSuperclass().getTable() );
732         unionSubclass.setTable( mytable );
733
734         log.info( "Mapping union-subclass: "
735             + unionSubclass.getEntityName()
736             + " -> "
737             + unionSubclass.getTable().getName() );
738
739         createClassProperties( node, unionSubclass, mappings, inheritedMetas );
740
741     }
742
743     public static void bindSubclass(Element node, Subclass subclass, Mappings mappings,
744             java.util.Map JavaDoc inheritedMetas) throws MappingException {
745
746         bindClass( node, subclass, mappings, inheritedMetas );
747         inheritedMetas = getMetas( node, inheritedMetas, true ); // get meta's from <subclass>
748

749         if ( subclass.getEntityPersisterClass() == null ) {
750             subclass.getRootClass().setEntityPersisterClass( SingleTableEntityPersister.class );
751         }
752
753         log.info( "Mapping subclass: "
754             + subclass.getEntityName()
755             + " -> "
756             + subclass.getTable().getName() );
757
758         // properties
759
createClassProperties( node, subclass, mappings, inheritedMetas );
760     }
761
762     private static String JavaDoc getClassTableName(PersistentClass model, Element node,