1 /*
2 * Hibernate, Relational Persistence for Idiomatic Java
3 *
4 * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
5 * indicated by the @author tags or express copyright attribution
6 * statements applied by the authors. All third-party contributions are
7 * distributed under license by Red Hat Middleware LLC.
8 *
9 * This copyrighted material is made available to anyone wishing to use, modify,
10 * copy, or redistribute it subject to the terms and conditions of the GNU
11 * Lesser General Public License, as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
16 * for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this distribution; if not, write to:
20 * Free Software Foundation, Inc.
21 * 51 Franklin Street, Fifth Floor
22 * Boston, MA 02110-1301 USA
23 *
24 */
25 package org.hibernate.mapping;
26
27 import java.io.Serializable;
28 import java.util;
29 import java.util.Set;
30
31 import org.hibernate.MappingException;
32 import org.hibernate.EntityMode;
33 import org.hibernate.dialect.Dialect;
34 import org.hibernate.engine.Mapping;
35 import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
36 import org.hibernate.sql.Alias;
37 import org.hibernate.util.EmptyIterator;
38 import org.hibernate.util.JoinedIterator;
39 import org.hibernate.util.ReflectHelper;
40 import org.hibernate.util.SingletonIterator;
41 import org.hibernate.util.StringHelper;
42
43 /**
44 * Mapping for an entity.
45 *
46 * @author Gavin King
47 */
48 public abstract class PersistentClass implements Serializable, Filterable, MetaAttributable {
49
50 private static final Alias PK_ALIAS = new Alias(15, "PK");
51
52 public static final String NULL_DISCRIMINATOR_MAPPING = "null";
53 public static final String NOT_NULL_DISCRIMINATOR_MAPPING = "not null";
54
55 private String entityName;
56
57 private String className;
58 private String proxyInterfaceName;
59
60 private String nodeName;
61
62 private String discriminatorValue;
63 private boolean lazy;
64 private ArrayList properties = new ArrayList();
65 private final ArrayList subclasses = new ArrayList();
66 private final ArrayList subclassProperties = new ArrayList();
67 private final ArrayList subclassTables = new ArrayList();
68 private boolean dynamicInsert;
69 private boolean dynamicUpdate;
70 private int batchSize=-1;
71 private boolean selectBeforeUpdate;
72 private java.util.Map metaAttributes;
73 private ArrayList joins = new ArrayList();
74 private final ArrayList subclassJoins = new ArrayList();
75 private final java.util.Map filters = new HashMap();
76 protected final java.util.Set synchronizedTables = new HashSet();
77 private String loaderName;
78 private Boolean isAbstract;
79 private boolean hasSubselectLoadableCollections;
80 private Component identifierMapper;
81
82 // Custom SQL
83 private String customSQLInsert;
84 private boolean customInsertCallable;
85 private ExecuteUpdateResultCheckStyle insertCheckStyle;
86 private String customSQLUpdate;
87 private boolean customUpdateCallable;
88 private ExecuteUpdateResultCheckStyle updateCheckStyle;
89 private String customSQLDelete;
90 private boolean customDeleteCallable;
91 private ExecuteUpdateResultCheckStyle deleteCheckStyle;
92
93 private String temporaryIdTableName;
94 private String temporaryIdTableDDL;
95
96 private java.util.Map tuplizerImpls;
97
98 protected int optimisticLockMode;
99
100 public String getClassName() {
101 return className;
102 }
103
104 public void setClassName(String className) {
105 this.className = className==null ? null : className.intern();
106 }
107
108 public String getProxyInterfaceName() {
109 return proxyInterfaceName;
110 }
111
112 public void setProxyInterfaceName(String proxyInterfaceName) {
113 this.proxyInterfaceName = proxyInterfaceName;
114 }
115
116 public Class getMappedClass() throws MappingException {
117 if (className==null) return null;
118 try {
119 return ReflectHelper.classForName(className);
120 }
121 catch (ClassNotFoundException cnfe) {
122 throw new MappingException("entity class not found: " + className, cnfe);
123 }
124 }
125
126 public Class getProxyInterface() {
127 if (proxyInterfaceName==null) return null;
128 try {
129 return ReflectHelper.classForName(proxyInterfaceName);
130 }
131 catch (ClassNotFoundException cnfe) {
132 throw new MappingException("proxy class not found: " + proxyInterfaceName, cnfe);
133 }
134 }
135 public boolean useDynamicInsert() {
136 return dynamicInsert;
137 }
138
139 abstract int nextSubclassId();
140 public abstract int getSubclassId();
141
142 public boolean useDynamicUpdate() {
143 return dynamicUpdate;
144 }
145
146 public void setDynamicInsert(boolean dynamicInsert) {
147 this.dynamicInsert = dynamicInsert;
148 }
149
150 public void setDynamicUpdate(boolean dynamicUpdate) {
151 this.dynamicUpdate = dynamicUpdate;
152 }
153
154
155 public String getDiscriminatorValue() {
156 return discriminatorValue;
157 }
158
159 public void addSubclass(Subclass subclass) throws MappingException {
160 // inheritance cycle detection (paranoid check)
161 PersistentClass superclass = getSuperclass();
162 while (superclass!=null) {
163 if( subclass.getEntityName().equals( superclass.getEntityName() ) ) {
164 throw new MappingException(
165 "Circular inheritance mapping detected: " +
166 subclass.getEntityName() +
167 " will have it self as superclass when extending " +
168 getEntityName()
169 );
170 }
171 superclass = superclass.getSuperclass();
172 }
173 subclasses.add(subclass);
174 }
175
176 public boolean hasSubclasses() {
177 return subclasses.size() > 0;
178 }
179
180 public int getSubclassSpan() {
181 int n = subclasses.size();
182 Iterator iter = subclasses.iterator();
183 while ( iter.hasNext() ) {
184 n += ( (Subclass) iter.next() ).getSubclassSpan();
185 }
186 return n;
187 }
188 /**
189 * Iterate over subclasses in a special 'order', most derived subclasses
190 * first.
191 */
192 public Iterator getSubclassIterator() {
193 Iterator[] iters = new Iterator[ subclasses.size() + 1 ];
194 Iterator iter = subclasses.iterator();
195 int i=0;
196 while ( iter.hasNext() ) {
197 iters[i++] = ( (Subclass) iter.next() ).getSubclassIterator();
198 }
199 iters[i] = subclasses.iterator();
200 return new JoinedIterator(iters);
201 }
202
203 public Iterator getSubclassClosureIterator() {
204 ArrayList iters = new ArrayList();
205 iters.add( new SingletonIterator(this) );
206 Iterator iter = getSubclassIterator();
207 while ( iter.hasNext() ) {
208 PersistentClass clazz = (PersistentClass) iter.next();
209 iters.add( clazz.getSubclassClosureIterator() );
210 }
211 return new JoinedIterator(iters);
212 }
213
214 public Table getIdentityTable() {
215 return getRootTable();
216 }
217
218 public Iterator getDirectSubclasses() {
219 return subclasses.iterator();
220 }
221
222 public void addProperty(Property p) {
223 properties.add(p);
224 p.setPersistentClass(this);
225 }
226
227 public abstract Table getTable();
228
229 public String getEntityName() {
230 return entityName;
231 }
232
233 public abstract boolean isMutable();
234 public abstract boolean hasIdentifierProperty();
235 public abstract Property getIdentifierProperty();
236 public abstract KeyValue getIdentifier();
237 public abstract Property getVersion();
238 public abstract Value getDiscriminator();
239 public abstract boolean isInherited();
240 public abstract boolean isPolymorphic();
241 public abstract boolean isVersioned();
242 public abstract String getCacheConcurrencyStrategy();
243 public abstract PersistentClass getSuperclass();
244 public abstract boolean isExplicitPolymorphism();
245 public abstract boolean isDiscriminatorInsertable();
246
247 public abstract Iterator getPropertyClosureIterator();
248 public abstract Iterator getTableClosureIterator();
249 public abstract Iterator getKeyClosureIterator();
250
251 protected void addSubclassProperty(Property prop) {
252 subclassProperties.add(prop);
253 }
254 protected void addSubclassJoin(Join join) {
255 subclassJoins.add(join);
256 }
257 protected void addSubclassTable(Table subclassTable) {
258 subclassTables.add(subclassTable);
259 }
260 public Iterator getSubclassPropertyClosureIterator() {
261 ArrayList iters = new ArrayList();
262 iters.add( getPropertyClosureIterator() );
263 iters.add( subclassProperties.iterator() );
264 for ( int i=0; i<subclassJoins.size(); i++ ) {
265 Join join = (Join) subclassJoins.get(i);
266 iters.add( join.getPropertyIterator() );
267 }
268 return new JoinedIterator(iters);
269 }
270 public Iterator getSubclassJoinClosureIterator() {
271 return new JoinedIterator( getJoinClosureIterator(), subclassJoins.iterator() );
272 }
273 public Iterator getSubclassTableClosureIterator() {
274 return new JoinedIterator( getTableClosureIterator(), subclassTables.iterator() );
275 }
276
277 public boolean isClassOrSuperclassJoin(Join join) {
278 return joins.contains(join);
279 }
280
281 public boolean isClassOrSuperclassTable(Table closureTable) {
282 return getTable()==closureTable;
283 }
284
285 public boolean isLazy() {
286 return lazy;
287 }
288
289 public void setLazy(boolean lazy) {
290 this.lazy = lazy;
291 }
292
293 public abstract boolean hasEmbeddedIdentifier();
294 public abstract Class getEntityPersisterClass();
295 public abstract void setEntityPersisterClass(Class classPersisterClass);
296 public abstract Table getRootTable();
297 public abstract RootClass getRootClass();
298 public abstract KeyValue getKey();
299
300 public void setDiscriminatorValue(String discriminatorValue) {
301 this.discriminatorValue = discriminatorValue;
302 }
303
304 public void setEntityName(String entityName) {
305 this.entityName = entityName==null ? null : entityName.intern();
306 }
307
308 public void createPrimaryKey() {
309 //Primary key constraint
310 PrimaryKey pk = new PrimaryKey();
311 Table table = getTable();
312 pk.setTable(table);
313 pk.setName( PK_ALIAS.toAliasString( table.getName() ) );
314 table.setPrimaryKey(pk);
315
316 pk.addColumns( getKey().getColumnIterator() );
317 }
318
319 public abstract String getWhere();
320
321 public int getBatchSize() {
322 return batchSize;
323 }
324
325 public void setBatchSize(int batchSize) {
326 this.batchSize = batchSize;
327 }
328
329 public boolean hasSelectBeforeUpdate() {
330 return selectBeforeUpdate;
331 }
332
333 public void setSelectBeforeUpdate(boolean selectBeforeUpdate) {
334 this.selectBeforeUpdate = selectBeforeUpdate;
335 }
336
337 /**
338 * Build an iterator of properties which are "referenceable".
339 *
340 * @see #getReferencedProperty for a discussion of "referenceable"
341 * @return The property iterator.
342 */
343 public Iterator getReferenceablePropertyIterator() {
344 return getPropertyClosureIterator();
345 }
346
347 /**
348 * Given a property path, locate the appropriate referenceable property reference.
349 * <p/>
350 * A referenceable property is a property which can be a target of a foreign-key
351 * mapping (an identifier or explcitly named in a property-ref).
352 *
353 * @param propertyPath The property path to resolve into a property reference.
354 * @return The property reference (never null).
355 * @throws MappingException If the property could not be found.
356 */
357 public Property getReferencedProperty(String propertyPath) throws MappingException {
358 try {
359 return getRecursiveProperty( propertyPath, getReferenceablePropertyIterator() );
360 }
361 catch ( MappingException e ) {
362 throw new MappingException(
363 "property-ref [" + propertyPath + "] not found on entity [" + getEntityName() + "]", e
364 );
365 }
366 }
367
368 public Property getRecursiveProperty(String propertyPath) throws MappingException {
369 try {
370 return getRecursiveProperty( propertyPath, getPropertyIterator() );
371 }
372 catch ( MappingException e ) {
373 throw new MappingException(
374 "property [" + propertyPath + "] not found on entity [" + getEntityName() + "]", e
375 );
376 }
377 }
378
379 private Property getRecursiveProperty(String propertyPath, Iterator iter) throws MappingException {
380 Property property = null;
381 StringTokenizer st = new StringTokenizer( propertyPath, ".", false );
382 try {
383 while ( st.hasMoreElements() ) {
384 final String element = ( String ) st.nextElement();
385 if ( property == null ) {
386 Property identifierProperty = getIdentifierProperty();
387 if ( identifierProperty != null && identifierProperty.getName().equals( element ) ) {
388 // we have a mapped identifier property and the root of
389 // the incoming property path matched that identifier
390 // property
391 property = identifierProperty;
392 }
393 else if ( identifierProperty == null && getIdentifierMapper() != null ) {
394 // we have an embedded composite identifier
395 try {
396 identifierProperty = getProperty( element, getIdentifierMapper().getPropertyIterator() );
397 if ( identifierProperty != null ) {
398 // the root of the incoming property path matched one
399 // of the embedded composite identifier properties
400 property = identifierProperty;
401 }
402 }
403 catch( MappingException ignore ) {
404 // ignore it...
405 }
406 }
407
408 if ( property == null ) {
409 property = getProperty( element, iter );
410 }
411 }
412 else {
413 //flat recursive algorithm
414 property = ( ( Component ) property.getValue() ).getProperty( element );
415 }
416 }
417 }
418 catch ( MappingException e ) {
419 throw new MappingException( "property [" + propertyPath + "] not found on entity [" + getEntityName() + "]" );
420 }
421
422 return property;
423 }
424
425 private Property getProperty(String propertyName, Iterator iterator) throws MappingException {
426 while ( iterator.hasNext() ) {
427 Property prop = (Property) iterator.next();
428 if ( prop.getName().equals( StringHelper.root(propertyName) ) ) {
429 return prop;
430 }
431 }
432 throw new MappingException( "property [" + propertyName + "] not found on entity [" + getEntityName() + "]" );
433 }
434
435 public Property getProperty(String propertyName) throws MappingException {
436 Iterator iter = getPropertyClosureIterator();
437 Property identifierProperty = getIdentifierProperty();
438 if ( identifierProperty != null
439 && identifierProperty.getName().equals( StringHelper.root(propertyName) )
440 ) {
441 return identifierProperty;
442 }
443 else {
444 return getProperty( propertyName, iter );
445 }
446 }
447
448 abstract public int getOptimisticLockMode();
449
450 public void setOptimisticLockMode(int optimisticLockMode) {
451 this.optimisticLockMode = optimisticLockMode;
452 }
453
454 public void validate(Mapping mapping) throws MappingException {
455 Iterator iter = getPropertyIterator();
456 while ( iter.hasNext() ) {
457 Property prop = (Property) iter.next();
458 if ( !prop.isValid(mapping) ) {
459 throw new MappingException(
460 "property mapping has wrong number of columns: " +
461 StringHelper.qualify( getEntityName(), prop.getName() ) +
462 " type: " +
463 prop.getType().getName()
464 );
465 }
466 }
467 checkPropertyDuplication();
468 checkColumnDuplication();
469 }
470
471 private void checkPropertyDuplication() throws MappingException {
472 HashSet names = new HashSet();
473 Iterator iter = getPropertyIterator();
474 while ( iter.hasNext() ) {
475 Property prop = (Property) iter.next();
476 if ( !names.add( prop.getName() ) ) {
477 throw new MappingException( "Duplicate property mapping of " + prop.getName() + " found in " + getEntityName());
478 }
479 }
480 }
481
482 public boolean isDiscriminatorValueNotNull() {
483 return NOT_NULL_DISCRIMINATOR_MAPPING.equals( getDiscriminatorValue() );
484 }
485 public boolean isDiscriminatorValueNull() {
486 return NULL_DISCRIMINATOR_MAPPING.equals( getDiscriminatorValue() );
487 }
488
489 public java.util.Map getMetaAttributes() {
490 return metaAttributes;
491 }
492
493 public void setMetaAttributes(java.util.Map metas) {
494 this.metaAttributes = metas;
495 }
496
497 public MetaAttribute getMetaAttribute(String name) {
498 return metaAttributes==null?null:(MetaAttribute) metaAttributes.get(name);
499 }
500
501 public String toString() {
502 return getClass().getName() + '(' + getEntityName() + ')';
503 }
504
505 public Iterator getJoinIterator() {
506 return joins.iterator();
507 }
508
509 public Iterator getJoinClosureIterator() {
510 return joins.iterator();
511 }
512
513 public void addJoin(Join join) {
514 joins.add(join);
515 join.setPersistentClass(this);
516 }
517
518 public int getJoinClosureSpan() {
519 return joins.size();
520 }
521
522 public int getPropertyClosureSpan() {
523 int span = properties.size();
524 for ( int i=0; i<joins.size(); i++ ) {
525 Join join = (Join) joins.get(i);
526 span += join.getPropertySpan();
527 }
528 return span;
529 }
530
531 public int getJoinNumber(Property prop) {
532 int result=1;
533 Iterator iter = getSubclassJoinClosureIterator();
534 while ( iter.hasNext() ) {
535 Join join = (Join) iter.next();
536 if ( join.containsProperty(prop) ) return result;
537 result++;
538 }
539 return 0;
540 }
541
542 /**
543 * Build an iterator over the properties defined on this class. The returned
544 * iterator only accounts for "normal" properties (i.e. non-identifier
545 * properties).
546 * <p/>
547 * Differs from {@link #getUnjoinedPropertyIterator} in that the iterator
548 * we return here will include properties defined as part of a join.
549 *
550 * @return An iterator over the "normal" properties.
551 */
552 public Iterator getPropertyIterator() {
553 ArrayList iterators = new ArrayList();
554 iterators.add( properties.iterator() );
555 for ( int i = 0; i < joins.size(); i++ ) {
556 Join join = ( Join ) joins.get( i );
557 iterators.add( join.getPropertyIterator() );
558 }
559 return new JoinedIterator( iterators );
560 }
561
562 /**
563 * Build an iterator over the properties defined on this class <b>which
564 * are not defined as part of a join</b>. As with {@link #getPropertyIterator},
565 * the returned iterator only accounts for non-identifier properties.
566 *
567 * @return An iterator over the non-joined "normal" properties.
568 */
569 public Iterator getUnjoinedPropertyIterator() {
570 return properties.iterator();
571 }
572
573 public void setCustomSQLInsert(String customSQLInsert, boolean callable, ExecuteUpdateResultCheckStyle checkStyle) {
574 this.customSQLInsert = customSQLInsert;
575 this.customInsertCallable = callable;
576 this.insertCheckStyle = checkStyle;
577 }
578
579 public String getCustomSQLInsert() {
580 return customSQLInsert;
581 }
582
583 public boolean isCustomInsertCallable() {
584 return customInsertCallable;
585 }
586
587 public ExecuteUpdateResultCheckStyle getCustomSQLInsertCheckStyle() {
588 return insertCheckStyle;
589 }
590
591 public void setCustomSQLUpdate(String customSQLUpdate, boolean callable, ExecuteUpdateResultCheckStyle checkStyle) {
592 this.customSQLUpdate = customSQLUpdate;
593 this.customUpdateCallable = callable;
594 this.updateCheckStyle = checkStyle;
595 }
596
597 public String getCustomSQLUpdate() {
598 return customSQLUpdate;
599 }
600
601 public boolean isCustomUpdateCallable() {
602 return customUpdateCallable;
603 }
604
605 public ExecuteUpdateResultCheckStyle getCustomSQLUpdateCheckStyle() {
606 return updateCheckStyle;
607 }
608
609 public void setCustomSQLDelete(String customSQLDelete, boolean callable, ExecuteUpdateResultCheckStyle checkStyle) {
610 this.customSQLDelete = customSQLDelete;
611 this.customDeleteCallable = callable;
612 this.deleteCheckStyle = checkStyle;
613 }
614
615 public String getCustomSQLDelete() {
616 return customSQLDelete;
617 }
618
619 public boolean isCustomDeleteCallable() {
620 return customDeleteCallable;
621 }
622
623 public ExecuteUpdateResultCheckStyle getCustomSQLDeleteCheckStyle() {
624 return deleteCheckStyle;
625 }
626
627 public void addFilter(String name, String condition) {
628 filters.put(name, condition);
629 }
630
631 public java.util.Map getFilterMap() {
632 return filters;
633 }
634
635 public boolean isForceDiscriminator() {
636 return false;
637 }
638
639 public abstract boolean isJoinedSubclass();
640
641 public String getLoaderName() {
642 return loaderName;
643 }
644
645 public void setLoaderName(String loaderName) {
646 this.loaderName = loaderName==null ? null : loaderName.intern();
647 }
648
649 public abstract java.util.Set getSynchronizedTables();
650
651 public void addSynchronizedTable(String table) {
652 synchronizedTables.add(table);
653 }
654
655 public Boolean isAbstract() {
656 return isAbstract;
657 }
658
659 public void setAbstract(Boolean isAbstract) {
660 this.isAbstract = isAbstract;
661 }
662
663 protected void checkColumnDuplication(Set distinctColumns, Iterator columns)
664 throws MappingException {
665 while ( columns.hasNext() ) {
666 Selectable columnOrFormula = (Selectable) columns.next();
667 if ( !columnOrFormula.isFormula() ) {
668 Column col = (Column) columnOrFormula;
669 if ( !distinctColumns.add( col.getName() ) ) {
670 throw new MappingException(
671 "Repeated column in mapping for entity: " +
672 getEntityName() +
673 " column: " +
674 col.getName() +
675 " (should be mapped with insert=\"false\" update=\"false\")"
676 );
677 }
678 }
679 }
680 }
681
682 protected void checkPropertyColumnDuplication(Set distinctColumns, Iterator properties)
683 throws MappingException {
684 while ( properties.hasNext() ) {
685 Property prop = (Property) properties.next();
686 if ( prop.getValue() instanceof Component ) { //TODO: remove use of instanceof!
687 Component component = (Component) prop.getValue();
688 checkPropertyColumnDuplication( distinctColumns, component.getPropertyIterator() );
689 }
690 else {
691 if ( prop.isUpdateable() || prop.isInsertable() ) {
692 checkColumnDuplication( distinctColumns, prop.getColumnIterator() );
693 }
694 }
695 }
696 }
697
698 protected Iterator getNonDuplicatedPropertyIterator() {
699 return getUnjoinedPropertyIterator();
700 }
701
702 protected Iterator getDiscriminatorColumnIterator() {
703 return EmptyIterator.INSTANCE;
704 }
705
706 protected void checkColumnDuplication() {
707 HashSet cols = new HashSet();
708 if (getIdentifierMapper() == null ) {
709 //an identifier mapper => getKey will be included in the getNonDuplicatedPropertyIterator()
710 //and checked later, so it needs to be excluded
711 checkColumnDuplication( cols, getKey().getColumnIterator() );
712 }
713 checkColumnDuplication( cols, getDiscriminatorColumnIterator() );
714 checkPropertyColumnDuplication( cols, getNonDuplicatedPropertyIterator() );
715 Iterator iter = getJoinIterator();
716 while ( iter.hasNext() ) {
717 cols.clear();
718 Join join = (Join) iter.next();
719 checkColumnDuplication( cols, join.getKey().getColumnIterator() );
720 checkPropertyColumnDuplication( cols, join.getPropertyIterator() );
721 }
722 }
723
724 public abstract Object accept(PersistentClassVisitor mv);
725
726 public String getNodeName() {
727 return nodeName;
728 }
729
730 public void setNodeName(String nodeName) {
731 this.nodeName = nodeName;
732 }
733
734 public boolean hasPojoRepresentation() {
735 return getClassName()!=null;
736 }
737
738 public boolean hasDom4jRepresentation() {
739 return getNodeName()!=null;
740 }
741
742 public boolean hasSubselectLoadableCollections() {
743 return hasSubselectLoadableCollections;
744 }
745
746 public void setSubselectLoadableCollections(boolean hasSubselectCollections) {
747 this.hasSubselectLoadableCollections = hasSubselectCollections;
748 }
749
750 public void prepareTemporaryTables(Mapping mapping, Dialect dialect) {
751 if ( dialect.supportsTemporaryTables() ) {
752 temporaryIdTableName = dialect.generateTemporaryTableName( getTable().getName() );
753 Table table = new Table();
754 table.setName( temporaryIdTableName );
755 Iterator itr = getTable().getPrimaryKey().getColumnIterator();
756 while( itr.hasNext() ) {
757 Column column = (Column) itr.next();
758 table.addColumn( (Column) column.clone() );
759 }
760 temporaryIdTableDDL = table.sqlTemporaryTableCreateString( dialect, mapping );
761 }
762 }
763
764 public String getTemporaryIdTableName() {
765 return temporaryIdTableName;
766 }
767
768 public String getTemporaryIdTableDDL() {
769 return temporaryIdTableDDL;
770 }
771
772 public Component getIdentifierMapper() {
773 return identifierMapper;
774 }
775
776 public boolean hasIdentifierMapper() {
777 return identifierMapper != null;
778 }
779
780 public void setIdentifierMapper(Component handle) {
781 this.identifierMapper = handle;
782 }
783
784 public void addTuplizer(EntityMode entityMode, String implClassName) {
785 if ( tuplizerImpls == null ) {
786 tuplizerImpls = new HashMap();
787 }
788 tuplizerImpls.put( entityMode, implClassName );
789 }
790
791 public String getTuplizerImplClassName(EntityMode mode) {
792 if ( tuplizerImpls == null ) return null;
793 return ( String ) tuplizerImpls.get( mode );
794 }
795
796 public java.util.Map getTuplizerMap() {
797 if ( tuplizerImpls == null ) {
798 return null;
799 }
800 return java.util.Collections.unmodifiableMap( tuplizerImpls );
801 }
802
803 public boolean hasNaturalId() {
804 Iterator props = getRootClass().getPropertyIterator();
805 while ( props.hasNext() ) {
806 if ( ( (Property) props.next() ).isNaturalIdentifier() ) {
807 return true;
808 }
809 }
810 return false;
811 }
812
813 public abstract boolean isLazyPropertiesCacheable();
814 }